Project

General

Profile

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

    
135
/****f* pfsense-utils/pfSenseHeader
136
 * NAME
137
 *   pfSenseHeader
138
 * INPUTS
139
 *   none
140
 * RESULT
141
 *   Javascript header change or browser Location:
142
 ******/
143
function pfSenseHeader($text) {
144
	global $_SERVER;
145
	if (isAjax()) {
146
		if ($_SERVER['HTTPS'] == "on") {
147
			$protocol = "https";
148
		} else {
149
			$protocol = "http";
150
		}
151

    
152
		$port = ":{$_SERVER['SERVER_PORT']}";
153
		if ($_SERVER['SERVER_PORT'] == "80" && $protocol == "http") {
154
			$port = "";
155
		}
156
		if ($_SERVER['SERVER_PORT'] == "443" && $protocol == "https") {
157
			$port = "";
158
		}
159
		$complete_url = "{$protocol}://{$_SERVER['HTTP_HOST']}{$port}/{$text}";
160
		echo "\ndocument.location.href = '{$complete_url}';\n";
161
	} else {
162
		header("Location: $text");
163
	}
164
}
165

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

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

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

    
184
		foreach ($cssfiles as $css) {
185
			// Don't display any login/logo page related CSS files
186
			if (strpos($css, "login") == 0 &&
187
			    strpos($css, "logo") == 0) {
188
				if (strpos($css, "BETA") != 0) {
189
					array_push($betacss, $css);
190
				} else if (strpos($css, "pfSense") != 0) {
191
					array_push($pfscss, $css);
192
				} else {
193
					array_push($usrcss, $css);
194
				}
195
			}
196
		}
197

    
198
		$css = array_merge($pfscss, $betacss, $usrcss);
199

    
200
		foreach ($css as $file) {
201
			$file = basename($file);
202
			$csslist[$file] = pathinfo($file, PATHINFO_FILENAME);
203
		}
204
	}
205
	return $csslist;
206
}
207

    
208
/****f* pfsense-utils/gen_webguicss_field
209
 * NAME
210
 *   gen_webguicss_field
211
 * INPUTS
212
 *   Pointer to section object
213
 *   Initial value for the field
214
 * RESULT
215
 *   no return value, section object is updated
216
 ******/
217
function gen_webguicss_field(&$section, $value) {
218

    
219
	$csslist = get_css_files();
220

    
221
	if (!isset($csslist[$value])) {
222
		$value = "pfSense.css";
223
	}
224

    
225
	$section->addInput(new Form_Select(
226
		'webguicss',
227
		'Theme',
228
		$value,
229
		$csslist
230
	))->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>');
231
}
232
function validate_webguicss_field(&$input_errors, $value) {
233
	$csslist = get_css_files();
234
	if (!isset($csslist[$value])) {
235
		$input_errors[] = gettext("The submitted Theme could not be found. Pick a different theme.");
236
	}
237
}
238

    
239
/****f* pfsense-utils/gen_webguifixedmenu_field
240
 * NAME
241
 *   gen_webguifixedmenu_field
242
 * INPUTS
243
 *   Pointer to section object
244
 *   Initial value for the field
245
 * RESULT
246
 *   no return value, section object is updated
247
 ******/
248
function gen_webguifixedmenu_field(&$section, $value) {
249

    
250
	$section->addInput(new Form_Select(
251
		'webguifixedmenu',
252
		'Top Navigation',
253
		$value,
254
		["" => gettext("Scrolls with page"), "fixed" => gettext("Fixed (Remains visible at top of page)")]
255
	))->setHelp("The fixed option is intended for large screens only.");
256
}
257
function validate_webguifixedmenu_field(&$input_errors, $value) {
258
	$valid_values = array("", "fixed");
259
	if (!in_array($value, $valid_values)) {
260
		$input_errors[] = gettext("The submitted Top Navigation value is invalid.");
261
	}
262
}
263

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

    
275
	$section->addInput(new Form_Select(
276
		'webguihostnamemenu',
277
		'Hostname in Menu',
278
		$value,
279
		["" => gettext("Default (No hostname)"), "hostonly" => gettext("Hostname only"), "fqdn" => gettext("Fully Qualified Domain Name")]
280
	))->setHelp("Replaces the Help menu title in the Navbar with the system hostname or FQDN.");
281
}
282
function validate_webguihostnamemenu_field(&$input_errors, $value) {
283
	$valid_values = array("", "hostonly", "fqdn");
284
	if (!in_array($value, $valid_values)) {
285
		$input_errors[] = gettext("The submitted Hostname in Menu value is invalid.");
286
	}
287
}
288

    
289
/****f* pfsense-utils/gen_dashboardcolumns_field
290
 * NAME
291
 *   gen_dashboardcolumns_field
292
 * INPUTS
293
 *   Pointer to section object
294
 *   Initial value for the field
295
 * RESULT
296
 *   no return value, section object is updated
297
 ******/
298
function gen_dashboardcolumns_field(&$section, $value) {
299

    
300
	if (((int) $value < 1) || ((int) $value > 6)) {
301
		$value = 2;
302
	}
303

    
304
	$section->addInput(new Form_Input(
305
		'dashboardcolumns',
306
		'Dashboard Columns',
307
		'number',
308
		$value,
309
		['min' => 1, 'max' => 6]
310
	));
311
}
312
function validate_dashboardcolumns_field(&$input_errors, $value) {
313
	if (!is_numericint($value) || ((int) $value < 1) || ((int) $value > 6)) {
314
		$input_errors[] = gettext("The submitted Dashboard Columns value is invalid.");
315
	}
316
}
317

    
318
/****f* pfsense-utils/gen_interfacessort_field
319
 * NAME
320
 *   gen_interfacessort_field
321
 * INPUTS
322
 *   Pointer to section object
323
 *   Initial value for the field
324
 * RESULT
325
 *   no return value, section object is updated
326
 ******/
327
function gen_interfacessort_field(&$section, $value) {
328

    
329
	$section->addInput(new Form_Checkbox(
330
		'interfacessort',
331
		'Interfaces Sort',
332
		'Sort Alphabetically',
333
		$value
334
	))->setHelp('If selected, lists of interfaces will be sorted by description, otherwise they are listed wan,lan,optn...');
335
}
336

    
337
/****f* pfsense-utils/gen_associatedpanels_fields
338
 * NAME
339
 *   gen_associatedpanels_fields
340
 * INPUTS
341
 *   Pointer to section object
342
 *   Initial value for each of the fields
343
 * RESULT
344
 *   no return value, section object is updated
345
 ******/
346
function gen_associatedpanels_fields(&$section, $value1, $value2, $value3, $value4) {
347

    
348
	$group = new Form_Group('Associated Panels Show/Hide');
349

    
350
	$group->add(new Form_Checkbox(
351
		'dashboardavailablewidgetspanel',
352
		null,
353
		'Available Widgets',
354
		$value1
355
		))->setHelp('Show the Available Widgets panel on the Dashboard.');
356

    
357
	$group->add(new Form_Checkbox(
358
		'systemlogsfilterpanel',
359
		null,
360
		'Log Filter',
361
		$value2
362
	))->setHelp('Show the Log Filter panel in System Logs.');
363

    
364
	$group->add(new Form_Checkbox(
365
		'systemlogsmanagelogpanel',
366
		null,
367
		'Manage Log',
368
		$value3
369
	))->setHelp('Show the Manage Log panel in System Logs.');
370

    
371
	$group->add(new Form_Checkbox(
372
		'statusmonitoringsettingspanel',
373
		null,
374
		'Monitoring Settings',
375
		$value4
376
	))->setHelp('Show the Settings panel in Status Monitoring.');
377

    
378
	$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.');
379

    
380
	$section->add($group);
381
}
382

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

    
394
	$section->addInput(new Form_Checkbox(
395
		'webguileftcolumnhyper',
396
		'Left Column Labels',
397
		'Active',
398
		$value
399
	))->setHelp('If selected, clicking a label in the left column will select/toggle the first item of the group.');
400
}
401

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

    
413
	$section->addInput(new Form_Checkbox(
414
		'disablealiaspopupdetail',
415
		'Alias Popups',
416
		'Disable details in alias popups',
417
		$value
418
	))->setHelp('If selected, the details in alias popups will not be shown, just the alias description (e.g. in Firewall Rules).');
419
}
420

    
421
/****f* pfsense-utils/gen_pagenamefirst_field
422
 * NAME
423
 *   gen_pagenamefirst_field
424
 * INPUTS
425
 *   Pointer to section object
426
 *   Initial value for the field
427
 * RESULT
428
 *   no return value, section object is updated
429
 ******/
430
function gen_pagenamefirst_field(&$section, $value) {
431

    
432
	$section->addInput(new Form_Checkbox(
433
		'pagenamefirst',
434
		'Browser tab text',
435
		'Display page name first in browser tab',
436
		$value
437
	))->setHelp('When this is unchecked, the browser tab shows the host name followed '.
438
		'by the current page. Check this box to display the current page followed by the '.
439
		'host name.');
440
}
441

    
442
/****f* pfsense-utils/gen_user_settings_fields
443
 * NAME
444
 *   gen_user_settings_fields
445
 * INPUTS
446
 *   Pointer to section object
447
 *   Array of initial values for the fields
448
 * RESULT
449
 *   no return value, section object is updated
450
 ******/
451
function gen_user_settings_fields(&$section, $pconfig) {
452

    
453
	gen_webguicss_field($section, $pconfig['webguicss']);
454
	gen_webguifixedmenu_field($section, $pconfig['webguifixedmenu']);
455
	gen_webguihostnamemenu_field($section, $pconfig['webguihostnamemenu']);
456
	gen_dashboardcolumns_field($section, $pconfig['dashboardcolumns']);
457
	gen_interfacessort_field($section, $pconfig['interfacessort']);
458
	gen_associatedpanels_fields(
459
		$section,
460
		$pconfig['dashboardavailablewidgetspanel'],
461
		$pconfig['systemlogsfilterpanel'],
462
		$pconfig['systemlogsmanagelogpanel'],
463
		$pconfig['statusmonitoringsettingspanel']);
464
	gen_webguileftcolumnhyper_field($section, $pconfig['webguileftcolumnhyper']);
465
	gen_disablealiaspopupdetail_field($section, $pconfig['disablealiaspopupdetail']);
466
	gen_pagenamefirst_field($section, $pconfig['pagenamefirst']);
467
}
468

    
469
/****f* pfsense-utils/gen_requirestatefilter_field
470
 * NAME
471
 *   gen_requirestatefilter_field
472
 * INPUTS
473
 *   Pointer to section object
474
 *   Initial value for the field
475
 * RESULT
476
 *   no return value, section object is updated
477
 ******/
478
function gen_requirestatefilter_field(&$section, $value) {
479
	$section->addInput(new Form_Checkbox(
480
		'requirestatefilter',
481
		'Require State Filter',
482
		'Do not display state table without a filter',
483
		$value
484
	))->setHelp('By default, the entire state table is displayed when entering '.
485
		'Diagnostics > States. This option requires a filter to be entered '.
486
		'before the states are displayed. Useful for systems with large state tables.');
487
}
488

    
489
/****f* pfsense-utils/gen_created_updated_fields
490
 * NAME
491
 *   gen_created_updated_fields
492
 * INPUTS
493
 *   Pointer to form object
494
 *   Array of created time and username
495
 *   Array of updated time and username
496
 * RESULT
497
 *   no return value, section object is added to form if needed
498
 ******/
499
function gen_created_updated_fields(&$form, $created, $updated, $tracker = 0) {
500
	$has_created_time = (isset($created['time']) && isset($created['username']));
501
	$has_updated_time = (isset($updated['time']) && isset($updated['username']));
502

    
503
	if ($has_created_time || $has_updated_time) {
504
		$section = new Form_Section('Rule Information');
505

    
506
		if (!empty($tracker)) {
507
			$section->addInput(new Form_StaticText(
508
				'Tracking ID',
509
				htmlspecialchars($tracker)
510
			));
511
		}
512

    
513
		if ($has_created_time) {
514
			$section->addInput(new Form_StaticText(
515
				'Created',
516
				htmlspecialchars(sprintf(
517
					gettext('%1$s by %2$s'),
518
					date(gettext("n/j/y H:i:s"), $created['time']),
519
					$created['username']))
520
			));
521
		}
522

    
523
		if ($has_updated_time) {
524
			$section->addInput(new Form_StaticText(
525
				'Updated',
526
				htmlspecialchars(sprintf(
527
					gettext('%1$s by %2$s'),
528
					date(gettext("n/j/y H:i:s"), $updated['time']),
529
					$updated['username']))
530
			));
531
		}
532

    
533
		$form->add($section);
534
	}
535
}
536

    
537
function hardware_offloading_applyflags($iface) {
538
	global $config;
539

    
540
	$flags_on = 0;
541
	$flags_off = 0;
542
	$options = pfSense_get_interface_addresses($iface);
543

    
544
	if (isset($config['system']['disablechecksumoffloading'])) {
545
		if (isset($options['encaps']['txcsum'])) {
546
			$flags_off |= IFCAP_TXCSUM;
547
		}
548
		if (isset($options['encaps']['rxcsum'])) {
549
			$flags_off |= IFCAP_RXCSUM;
550
		}
551
		if (isset($options['encaps']['txcsum6'])) {
552
			$flags_off |= IFCAP_TXCSUM_IPV6;
553
		}
554
		if (isset($options['encaps']['rxcsum6'])) {
555
			$flags_off |= IFCAP_RXCSUM_IPV6;
556
		}
557
	} else {
558
		if (isset($options['caps']['txcsum'])) {
559
			$flags_on |= IFCAP_TXCSUM;
560
		}
561
		if (isset($options['caps']['rxcsum'])) {
562
			$flags_on |= IFCAP_RXCSUM;
563
		}
564
		if (isset($options['caps']['txcsum6'])) {
565
			$flags_on |= IFCAP_TXCSUM_IPV6;
566
		}
567
		if (isset($options['caps']['rxcsum6'])) {
568
			$flags_on |= IFCAP_RXCSUM_IPV6;
569
		}
570
	}
571

    
572
	if (isset($config['system']['disablesegmentationoffloading'])) {
573
		$flags_off |= IFCAP_TSO;
574
	} else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6'])) {
575
		$flags_on |= IFCAP_TSO;
576
	}
577

    
578
	if (isset($config['system']['disablelargereceiveoffloading'])) {
579
		$flags_off |= IFCAP_LRO;
580
	} else if (isset($options['caps']['lro'])) {
581
		$flags_on |= IFCAP_LRO;
582
	}
583

    
584
	pfSense_interface_capabilities($iface, -$flags_off);
585
	pfSense_interface_capabilities($iface, $flags_on);
586
}
587

    
588
/****f* pfsense-utils/enable_hardware_offloading
589
 * NAME
590
 *   enable_hardware_offloading - Enable a NIC's supported hardware features.
591
 * INPUTS
592
 *   $interface	- string containing the physical interface to work on.
593
 * RESULT
594
 *   null
595
 * NOTES
596
 *   This function only supports the fxp driver's loadable microcode.
597
 ******/
598
function enable_hardware_offloading($interface) {
599
	global $g, $config;
600

    
601
	$int = get_real_interface($interface);
602
	if (empty($int)) {
603
		return;
604
	}
605

    
606
	if (!isset($config['system']['do_not_use_nic_microcode'])) {
607
		/* translate wan, lan, opt -> real interface if needed */
608
		$int_family = preg_split("/[0-9]+/", $int);
609
		$supported_ints = array('fxp');
610
		if (in_array($int_family, $supported_ints)) {
611
			if (does_interface_exist($int)) {
612
				pfSense_interface_flags($int, IFF_LINK0);
613
			}
614
		}
615
	}
616

    
617
	/* This is mostly for vlans and ppp types */
618
	$realhwif = get_parent_interface($interface);
619
	if ($realhwif[0] == $int) {
620
		hardware_offloading_applyflags($int);
621
	} else {
622
		hardware_offloading_applyflags($realhwif[0]);
623
		hardware_offloading_applyflags($int);
624
	}
625
}
626

    
627
/****f* pfsense-utils/is_alias_inuse
628
 * NAME
629
 *   checks to see if an alias is currently in use by a rule
630
 * INPUTS
631
 *
632
 * RESULT
633
 *   true or false
634
 * NOTES
635
 *
636
 ******/
637
function is_alias_inuse($alias) {
638
	global $g, $config;
639

    
640
	if ($alias == "") {
641
		return false;
642
	}
643
	/* loop through firewall rules looking for alias in use */
644
	if (is_array($config['filter']['rule'])) {
645
		foreach ($config['filter']['rule'] as $rule) {
646
			if ($rule['source']['address']) {
647
				if ($rule['source']['address'] == $alias) {
648
					return true;
649
				}
650
			}
651
			if ($rule['destination']['address']) {
652
				if ($rule['destination']['address'] == $alias) {
653
					return true;
654
				}
655
			}
656
		}
657
	}
658
	/* loop through nat rules looking for alias in use */
659
	if (is_array($config['nat']['rule'])) {
660
		foreach ($config['nat']['rule'] as $rule) {
661
			if ($rule['target'] && $rule['target'] == $alias) {
662
				return true;
663
			}
664
			if ($rule['source']['address'] && $rule['source']['address'] == $alias) {
665
				return true;
666
			}
667
			if ($rule['destination']['address'] && $rule['destination']['address'] == $alias) {
668
				return true;
669
			}
670
		}
671
	}
672
	return false;
673
}
674

    
675
/****f* pfsense-utils/is_schedule_inuse
676
 * NAME
677
 *   checks to see if a schedule is currently in use by a rule
678
 * INPUTS
679
 *
680
 * RESULT
681
 *   true or false
682
 * NOTES
683
 *
684
 ******/
685
function is_schedule_inuse($schedule) {
686
	global $g, $config;
687

    
688
	if ($schedule == "") {
689
		return false;
690
	}
691
	/* loop through firewall rules looking for schedule in use */
692
	if (is_array($config['filter']['rule'])) {
693
		foreach ($config['filter']['rule'] as $rule) {
694
			if ($rule['sched'] == $schedule) {
695
				return true;
696
			}
697
		}
698
	}
699
	return false;
700
}
701

    
702
/****f* pfsense-utils/setup_microcode
703
 * NAME
704
 *   enumerates all interfaces and calls enable_hardware_offloading which
705
 *   enables a NIC's supported hardware features.
706
 * INPUTS
707
 *
708
 * RESULT
709
 *   null
710
 * NOTES
711
 *   This function only supports the fxp driver's loadable microcode.
712
 ******/
713
function setup_microcode() {
714

    
715
	/* if list */
716
	$iflist = get_configured_interface_list(true);
717
	foreach ($iflist as $if => $ifdescr) {
718
		enable_hardware_offloading($if);
719
	}
720
	unset($iflist);
721
}
722

    
723
/****f* pfsense-utils/get_carp_status
724
 * NAME
725
 *   get_carp_status - Return whether CARP is enabled or disabled.
726
 * RESULT
727
 *   boolean	- true if CARP is enabled, false if otherwise.
728
 ******/
729
function get_carp_status() {
730
	/* grab the current status of carp */
731
	$status = get_single_sysctl('net.inet.carp.allow');
732
	return (intval($status) > 0);
733
}
734

    
735
/*
736
 * convert_ip_to_network_format($ip, $subnet): converts an ip address to network form
737

    
738
 */
739
function convert_ip_to_network_format($ip, $subnet) {
740
	$ipsplit = explode('.', $ip);
741
	$string = $ipsplit[0] . "." . $ipsplit[1] . "." . $ipsplit[2] . ".0/" . $subnet;
742
	return $string;
743
}
744

    
745
/*
746
 * get_carp_interface_status($carpid): returns the status of a carp uniqid
747
 */
748
function get_carp_interface_status($carpid) {
749

    
750
	$carpiface = get_configured_vip_interface($carpid);
751
	if ($carpiface == NULL)
752
		return "";
753
	$interface = get_real_interface($carpiface);
754
	if ($interface == NULL)
755
		return "";
756
	$vip = get_configured_vip($carpid);
757
	if ($vip == NULL || !isset($vip['vhid']))
758
		return "";
759

    
760
	$vhid = $vip['vhid'];
761
	$carp_query = '';
762
	$_gb = exec("/sbin/ifconfig {$interface} | /usr/bin/grep \"carp:.* vhid {$vhid} \"", $carp_query);
763
	foreach ($carp_query as $int) {
764
		if (stripos($int, "MASTER"))
765
			return "MASTER";
766
		elseif (stripos($int, "BACKUP"))
767
			return "BACKUP";
768
		elseif (stripos($int, "INIT"))
769
			return "INIT";
770
	}
771

    
772
	return "";
773
}
774

    
775
/*
776
 * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
777
 */
778
function get_pfsync_interface_status($pfsyncinterface) {
779
	if (!does_interface_exist($pfsyncinterface)) {
780
		return;
781
	}
782

    
783
	return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
784
}
785

    
786
/*
787
 * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
788
 */
789
function add_rule_to_anchor($anchor, $rule, $label) {
790
	mwexec("echo " . escapeshellarg($rule) . " | /sbin/pfctl -a " . escapeshellarg($anchor) . ":" . escapeshellarg($label) . " -f -");
791
}
792

    
793
/*
794
 * remove_text_from_file
795
 * remove $text from file $file
796
 */
797
function remove_text_from_file($file, $text) {
798
	if (!file_exists($file) && !is_writable($file)) {
799
		return;
800
	}
801
	$filecontents = file_get_contents($file);
802
	$text = str_replace($text, "", $filecontents);
803
	@file_put_contents($file, $text);
804
}
805

    
806
/*
807
 *   after_sync_bump_adv_skew(): create skew values by 1S
808
 */
809
function after_sync_bump_adv_skew() {
810
	global $config, $g;
811
	$processed_skew = 1;
812
	init_config_arr(array('virtualip', 'vip'));
813
	$a_vip = &$config['virtualip']['vip'];
814
	foreach ($a_vip as $vipent) {
815
		if ($vipent['advskew'] <> "") {
816
			$processed_skew = 1;
817
			$vipent['advskew'] = $vipent['advskew']+1;
818
		}
819
	}
820
	if ($processed_skew == 1) {
821
		write_config(gettext("After synch increase advertising skew"));
822
	}
823
}
824

    
825
/*
826
 * get_filename_from_url($url): converts a url to its filename.
827
 */
828
function get_filename_from_url($url) {
829
	return basename($url);
830
}
831

    
832
/*
833
 *   get_dir: return an array of $dir
834
 */
835
function get_dir($dir) {
836
	$dir_array = array();
837
	$d = dir($dir);
838
	if (!is_object($d)) {
839
		return array();
840
	}
841
	while (false !== ($entry = $d->read())) {
842
		array_push($dir_array, $entry);
843
	}
844
	$d->close();
845
	return $dir_array;
846
}
847

    
848
/****f* pfsense-utils/WakeOnLan
849
 * NAME
850
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
851
 * RESULT
852
 *   true/false - true if the operation was successful
853
 ******/
854
function WakeOnLan($addr, $mac) {
855
	$addr_byte = explode(':', $mac);
856
	$hw_addr = '';
857

    
858
	for ($a = 0; $a < 6; $a++) {
859
		$hw_addr .= chr(hexdec($addr_byte[$a]));
860
	}
861

    
862
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
863

    
864
	for ($a = 1; $a <= 16; $a++) {
865
		$msg .= $hw_addr;
866
	}
867

    
868
	// send it to the broadcast address using UDP
869
	$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
870
	if ($s == false) {
871
		log_error(gettext("Error creating socket!"));
872
		log_error(sprintf(gettext("Error code is '%1\$s' - %2\$s"), socket_last_error($s), socket_strerror(socket_last_error($s))));
873
	} else {
874
		// setting a broadcast option to socket:
875
		$opt_ret = socket_set_option($s, 1, 6, TRUE);
876
		if ($opt_ret < 0) {
877
			log_error(sprintf(gettext("setsockopt() failed, error: %s"), strerror($opt_ret)));
878
		}
879
		$e = socket_sendto($s, $msg, strlen($msg), 0, $addr, 2050);
880
		socket_close($s);
881
		log_error(sprintf(gettext('Magic Packet sent (%1$s) to (%2$s) MAC=%3$s'), $e, $addr, $mac));
882
		return true;
883
	}
884

    
885
	return false;
886
}
887

    
888
/*
889
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
890
 *					 Useful for finding paths and stripping file extensions.
891
 */
892
function reverse_strrchr($haystack, $needle) {
893
	if (!is_string($haystack)) {
894
		return;
895
	}
896
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
897
}
898

    
899
/*
900
 *  backup_config_section($section): returns as an xml file string of
901
 *                                   the configuration section
902
 */
903
function backup_config_section($section_name) {
904
	global $config;
905
	$new_section = &$config[$section_name];
906
	/* generate configuration XML */
907
	$xmlconfig = dump_xml_config($new_section, $section_name);
908
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
909
	return $xmlconfig;
910
}
911

    
912
/*
913
 *  restore_config_section($section_name, new_contents): restore a configuration section,
914
 *                                                  and write the configuration out
915
 *                                                  to disk/cf.
916
 */
917
function restore_config_section($section_name, $new_contents) {
918
	global $config, $g;
919
	$fout = fopen("{$g['tmp_path']}/tmpxml", "w");
920
	fwrite($fout, $new_contents);
921
	fclose($fout);
922

    
923
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
924
	if ($xml['pfsense']) {
925
		$xml = $xml['pfsense'];
926
	}
927
	else if ($xml['m0n0wall']) {
928
		$xml = $xml['m0n0wall'];
929
	}
930
	if ($xml[$section_name]) {
931
		$section_xml = $xml[$section_name];
932
	} else {
933
		$section_xml = -1;
934
	}
935

    
936
	@unlink($g['tmp_path'] . "/tmpxml");
937
	if ($section_xml === -1) {
938
		return false;
939
	}
940

    
941
	/* Save current pkg repo to re-add on new config */
942
	unset($pkg_repo_conf_path);
943
	if ($section_name == "system" &&
944
	    isset($config['system']['pkg_repo_conf_path'])) {
945
		$pkg_repo_conf_path = $config['system']['pkg_repo_conf_path'];
946
	}
947

    
948
	$config[$section_name] = &$section_xml;
949
	if (file_exists("{$g['tmp_path']}/config.cache")) {
950
		unlink("{$g['tmp_path']}/config.cache");
951
	}
952

    
953
	/* Restore previously pkg repo configured */
954
	if ($section_name == "system") {
955
		if (isset($pkg_repo_conf_path)) {
956
			$config['system']['pkg_repo_conf_path'] =
957
			    $pkg_repo_conf_path;
958
		} elseif (isset($config['system']['pkg_repo_conf_path'])) {
959
			unset($config['system']['pkg_repo_conf_path']);
960
		}
961
	}
962

    
963
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
964
	disable_security_checks();
965
	return true;
966
}
967

    
968
/*
969
 *  merge_config_section($section_name, new_contents):   restore a configuration section,
970
 *                                                  and write the configuration out
971
 *                                                  to disk/cf.  But preserve the prior
972
 * 													structure if needed
973
 */
974
function merge_config_section($section_name, $new_contents) {
975
	global $config;
976
	$fname = get_tmp_filename();
977
	$fout = fopen($fname, "w");
978
	fwrite($fout, $new_contents);
979
	fclose($fout);
980
	$section_xml = parse_xml_config($fname, $section_name);
981
	$config[$section_name] = $section_xml;
982
	unlink($fname);
983
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
984
	disable_security_checks();
985
	return;
986
}
987

    
988
/*
989
 * rmdir_recursive($path, $follow_links=false)
990
 * Recursively remove a directory tree (rm -rf path)
991
 * This is for directories _only_
992
 */
993
function rmdir_recursive($path, $follow_links=false) {
994
	$to_do = glob($path);
995
	if (!is_array($to_do)) {
996
		$to_do = array($to_do);
997
	}
998
	foreach ($to_do as $workingdir) { // Handle wildcards by foreaching.
999
		if (file_exists($workingdir)) {
1000
			if (is_dir($workingdir)) {
1001
				$dir = opendir($workingdir);
1002
				while ($entry = readdir($dir)) {
1003
					if (is_file("$workingdir/$entry") || ((!$follow_links) && is_link("$workingdir/$entry"))) {
1004
						unlink("$workingdir/$entry");
1005
					} elseif (is_dir("$workingdir/$entry") && $entry != '.' && $entry != '..') {
1006
						rmdir_recursive("$workingdir/$entry");
1007
					}
1008
				}
1009
				closedir($dir);
1010
				rmdir($workingdir);
1011
			} elseif (is_file($workingdir)) {
1012
				unlink($workingdir);
1013
			}
1014
		}
1015
	}
1016
	return;
1017
}
1018

    
1019
/*
1020
 * host_firmware_version(): Return the versions used in this install
1021
 */
1022
function host_firmware_version($tocheck = "") {
1023
	global $g, $config;
1024

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

    
1027
	return array(
1028
		"firmware" => array("version" => $g['product_version']),
1029
		"kernel"   => array("version" => $os_version),
1030
		"base"     => array("version" => $os_version),
1031
		"platform" => $g['platform'],
1032
		"config_version" => $config['version']
1033
	);
1034
}
1035

    
1036
function get_disk_info() {
1037
	$diskout = "";
1038
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
1039
	return explode(' ', $diskout[0]);
1040
}
1041

    
1042
/****f* pfsense-utils/strncpy
1043
 * NAME
1044
 *   strncpy - copy strings
1045
 * INPUTS
1046
 *   &$dst, $src, $length
1047
 * RESULT
1048
 *   none
1049
 ******/
1050
function strncpy(&$dst, $src, $length) {
1051
	if (strlen($src) > $length) {
1052
		$dst = substr($src, 0, $length);
1053
	} else {
1054
		$dst = $src;
1055
	}
1056
}
1057

    
1058
/****f* pfsense-utils/reload_interfaces_sync
1059
 * NAME
1060
 *   reload_interfaces - reload all interfaces
1061
 * INPUTS
1062
 *   none
1063
 * RESULT
1064
 *   none
1065
 ******/
1066
function reload_interfaces_sync() {
1067
	global $config, $g;
1068

    
1069
	if ($g['debug']) {
1070
		log_error(gettext("reload_interfaces_sync() is starting."));
1071
	}
1072

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

    
1076
	/* enable routing */
1077
	system_routing_enable();
1078
	if ($g['debug']) {
1079
		log_error(gettext("Enabling system routing"));
1080
	}
1081

    
1082
	if ($g['debug']) {
1083
		log_error(gettext("Cleaning up Interfaces"));
1084
	}
1085

    
1086
	/* set up interfaces */
1087
	interfaces_configure();
1088
}
1089

    
1090
/****f* pfsense-utils/reload_all
1091
 * NAME
1092
 *   reload_all - triggers a reload of all settings
1093
 *   * INPUTS
1094
 *   none
1095
 * RESULT
1096
 *   none
1097
 ******/
1098
function reload_all() {
1099
	send_event("service reload all");
1100
}
1101

    
1102
/****f* pfsense-utils/reload_interfaces
1103
 * NAME
1104
 *   reload_interfaces - triggers a reload of all interfaces
1105
 * INPUTS
1106
 *   none
1107
 * RESULT
1108
 *   none
1109
 ******/
1110
function reload_interfaces() {
1111
	send_event("interface all reload");
1112
}
1113

    
1114
/****f* pfsense-utils/reload_all_sync
1115
 * NAME
1116
 *   reload_all - reload all settings
1117
 *   * INPUTS
1118
 *   none
1119
 * RESULT
1120
 *   none
1121
 ******/
1122
function reload_all_sync() {
1123
	global $config, $g;
1124

    
1125
	/* parse config.xml again */
1126
	$config = parse_config(true);
1127

    
1128
	/* set up our timezone */
1129
	system_timezone_configure();
1130

    
1131
	/* set up our hostname */
1132
	system_hostname_configure();
1133

    
1134
	/* make hosts file */
1135
	system_hosts_generate();
1136

    
1137
	/* generate resolv.conf */
1138
	system_resolvconf_generate();
1139

    
1140
	/* enable routing */
1141
	system_routing_enable();
1142

    
1143
	/* set up interfaces */
1144
	interfaces_configure();
1145

    
1146
	/* start dyndns service */
1147
	services_dyndns_configure();
1148

    
1149
	/* configure cron service */
1150
	configure_cron();
1151

    
1152
	/* start the NTP client */
1153
	system_ntp_configure();
1154

    
1155
	/* sync pw database */
1156
	unlink_if_exists("/etc/spwd.db.tmp");
1157
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
1158

    
1159
	/* restart sshd */
1160
	send_event("service restart sshd");
1161

    
1162
	/* restart webConfigurator if needed */
1163
	send_event("service restart webgui");
1164
}
1165

    
1166
function load_loader_conf($loader_conf = NULL, $local = false) {
1167

    
1168
	if ($loader_conf == NULL) {
1169
		return (NULL);
1170
	}
1171
	if (file_exists($loader_conf)) {
1172
		$input = file_get_contents($loader_conf);
1173
	} else {
1174
		$input = "";
1175
	}
1176

    
1177
	$input_split = explode("\n", $input);
1178

    
1179
	/*
1180
	 * Loop through and only add lines that are not empty and not
1181
	 * managed by us.
1182
	 */
1183
	$data = array();
1184
	/* These values should be removed from loader.conf and loader.conf.local
1185
	 * As they will be replaced when necessary. */
1186
	$remove = array("hw.usb.no_pf", "hint.mdio.0.at", "hint.e6000sw.0",
1187
	    "hw.e6000sw.default_disabled", "vm.pmap.pti",
1188
	    "net.pf.request_maxcount");
1189
	if (!$local) {
1190
		/* These values should only be filtered in loader.conf, not .local */
1191
		$remove = array_merge($remove,
1192
		    array("autoboot_delay", "console", "comconsole_speed",
1193
		    "boot_multicons", "boot_serial", "hint.uart.0.flags",
1194
		    "hint.uart.1.flags"));
1195
	}
1196
	foreach ($input_split as $line) {
1197
		if (empty($line)) {
1198
			continue;
1199
		}
1200
		$skip = false;
1201
		list($name, $value) = explode('=', $line, 2);
1202
		foreach($remove as $rid => $rkey) {
1203
			if (strncasecmp(trim($name), $rkey, strlen($rkey)) == 0) {
1204
				$skip = true;
1205
				break;
1206
			}
1207
		}
1208
		if (!$skip) {
1209
			$data[] = $line;
1210
		}
1211
	}
1212

    
1213
	return ($data);
1214
}
1215

    
1216
function setup_loader_settings($path = "", $upgrade = false) {
1217
	global $g, $config;
1218

    
1219
	$boot_config_file = "{$path}/boot.config";
1220
	$loader_conf_file = "{$path}/boot/loader.conf";
1221

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

    
1224
	$vga_only = false;
1225
	$serial_only = false;
1226
	$specific_platform = system_identify_specific_platform();
1227
	$video_console_type = (get_single_sysctl("machdep.bootmethod") == "UEFI") ? "efi" : "vidconsole";
1228
	if ($specific_platform['name'] == 'XG-1540') {
1229
		$vga_only = true;
1230
	} elseif ($specific_platform['name'] == 'Turbot Dual-E') {
1231
		$g['primaryconsole_force'] = "video";
1232
	} elseif ($specific_platform['name'] == 'RCC-VE' ||
1233
	    $specific_platform['name'] == 'RCC' ||
1234
	    $specific_platform['name'] == 'SG-2220' ||
1235
	    $specific_platform['name'] == 'apu2') {
1236
		$serial_only = true;
1237
	}
1238

    
1239
	/* Serial console - write out /boot.config */
1240
	if (file_exists($boot_config_file)) {
1241
		$boot_config = file_get_contents($boot_config_file);
1242
	} else {
1243
		$boot_config = "";
1244
	}
1245
	$boot_config_split = explode("\n", $boot_config);
1246
	$data = array();
1247
	foreach ($boot_config_split as $bcs) {
1248
		/* Ignore -D and -h lines now */
1249
		if (!empty($bcs) && !stristr($bcs, "-D") &&
1250
		    !stristr($bcs, "-h")) {
1251
			$data[] = $bcs;
1252
		}
1253
	}
1254
	if ($serial_only === true) {
1255
		$data[] = "-S{$serialspeed} -h";
1256
	} elseif (is_serial_enabled()) {
1257
		$data[] = "-S{$serialspeed} -D";
1258
	}
1259

    
1260
	if (empty($data)) {
1261
		@unlink($boot_conf_file);
1262
	} else {
1263
		safe_write_file($boot_config_file, $data);
1264
	}
1265
	unset($data, $boot_config, $boot_config_file, $boot_config_split);
1266

    
1267
	/* Serial console - write out /boot/loader.conf */
1268
	if ($upgrade) {
1269
		system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1270
	}
1271

    
1272
	$data = load_loader_conf($loader_conf_file, false);
1273
	if ($serial_only === true) {
1274
		$data[] = 'boot_serial="YES"';
1275
		$data[] = 'console="comconsole"';
1276
		$data[] = 'comconsole_speed="' . $serialspeed . '"';
1277
	} elseif ($vga_only === true) {
1278
		$data[] = "console=\"{$video_console_type}\"";
1279
	} elseif (is_serial_enabled()) {
1280
		$data[] = 'boot_multicons="YES"';
1281
		$data[] = 'boot_serial="YES"';
1282
		$primaryconsole = isset($g['primaryconsole_force']) ?
1283
		    $g['primaryconsole_force'] :
1284
		    $config['system']['primaryconsole'];
1285
		switch ($primaryconsole) {
1286
			case "video":
1287
				$data[] = "console=\"{$video_console_type},comconsole\"";
1288
				break;
1289
			case "serial":
1290
			default:
1291
				$data[] = "console=\"comconsole,{$video_console_type}\"";
1292
		}
1293
		$data[] = 'comconsole_speed="' . $serialspeed . '"';
1294
	}
1295

    
1296
	if ($specific_platform['name'] == 'RCC-VE' ||
1297
	    $specific_platform['name'] == 'RCC' ||
1298
	    $specific_platform['name'] == 'SG-2220') {
1299
		$data[] = 'comconsole_port="0x2F8"';
1300
		$data[] = 'hint.uart.0.flags="0x00"';
1301
		$data[] = 'hint.uart.1.flags="0x10"';
1302
	}
1303
	$data[] = 'autoboot_delay="3"';
1304
	$data[] = 'hw.usb.no_pf="1"';
1305
	if (isset($config['system']['pti_disabled'])) {
1306
		$data[] = 'vm.pmap.pti="0"';
1307
	}
1308

    
1309
	if (isset($config['system']['maximumtableentries'])) {
1310
		$maximumtableentries = $config['system']['maximumtableentries'];
1311
	} else {
1312
		$maximumtableentries = pfsense_default_table_entries_size();
1313
	}
1314
	$data[] = 'net.pf.request_maxcount="' .  $maximumtableentries . '"';
1315

    
1316
	safe_write_file($loader_conf_file, $data);
1317

    
1318
	/* Filter loader.conf.local to avoid duplicate settings. */
1319
	$loader_conf_file = "{$path}/boot/loader.conf.local";
1320
	$data = load_loader_conf($loader_conf_file, true);
1321
	if (empty($data)) {
1322
		@unlink($loader_conf_file);
1323
	} else {
1324
		safe_write_file($loader_conf_file, $data);
1325
	}
1326

    
1327
}
1328

    
1329
function console_configure($when = "save", $path = "") {
1330
	global $config;
1331
	$ttys_file = "{$path}/etc/ttys";
1332

    
1333
	/* Update the loader settings. */
1334
	setup_loader_settings($path, ($when == "upgrade"));
1335

    
1336
	$ttys = file_get_contents($ttys_file);
1337
	$ttys_split = explode("\n", $ttys);
1338

    
1339
	$data = array();
1340

    
1341
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1342

    
1343
	if (isset($config['system']['disableconsolemenu'])) {
1344
		$console_type = 'Pc';
1345
		$serial_type = '3wire';
1346
	} else {
1347
		$console_type = 'al.Pc';
1348
		$serial_type = 'al.3wire';
1349
	}
1350

    
1351
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1352
	$ttyv0_line =
1353
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\txterm\tonifexists secure";
1354
	$ttyu_line =
1355
	    "\"/usr/libexec/getty {$serial_type}\"\tvt100\t{$on_off}\tsecure";
1356

    
1357
	$found = array();
1358

    
1359
	foreach ($ttys_split as $tty) {
1360
		/* Ignore blank lines */
1361
		if (empty($tty)) {
1362
			continue;
1363
		}
1364

    
1365
		if (stristr($tty, "ttyv0")) {
1366
			$found['ttyv0'] = 1;
1367
			$data[] = $ttyv0_line;
1368
		} elseif (stristr($tty, "ttyu")) {
1369
			$ttyn = substr($tty, 0, 5);
1370
			$found[$ttyn] = 1;
1371
			$data[] = "{$ttyn}\t{$ttyu_line}";
1372
		} elseif (substr($tty, 0, 7) == 'console') {
1373
			$found['console'] = 1;
1374
			$data[] = $tty;
1375
		} else {
1376
			$data[] = $tty;
1377
		}
1378
	}
1379
	unset($on_off, $console_type, $serial_type);
1380

    
1381
	/* Detect missing main lines on original file and try to rebuild it */
1382
	$items = array(
1383
		'console',
1384
		'ttyv0',
1385
		'ttyu0',
1386
		'ttyu1',
1387
		'ttyu2',
1388
		'ttyu3'
1389
	);
1390

    
1391
	foreach ($items as $item) {
1392
		if (isset($found[$item])) {
1393
			continue;
1394
		}
1395

    
1396
		if ($item == 'console') {
1397
			$data[] = $console_line;
1398
		} elseif ($item == 'ttyv0') {
1399
			$data[] = $ttyv0_line;
1400
		} else {
1401
			$data[] = "{$item}\t{$ttyu_line}";
1402
		}
1403
	}
1404

    
1405
	safe_write_file($ttys_file, $data);
1406

    
1407
	unset($ttys, $ttys_file, $ttys_split, $data);
1408

    
1409
	if ($when != "upgrade") {
1410
		reload_ttys();
1411
	}
1412

    
1413
	return;
1414
}
1415

    
1416
function is_serial_enabled() {
1417
	global $g, $config;
1418

    
1419
	if (!isset($g['enableserial_force']) &&
1420
	    !isset($config['system']['enableserial'])) {
1421
		return false;
1422
	}
1423

    
1424
	return true;
1425
}
1426

    
1427
function reload_ttys() {
1428
	// Send a HUP signal to init will make it reload /etc/ttys
1429
	posix_kill(1, SIGHUP);
1430
}
1431

    
1432
function print_value_list($list, $count = 10, $separator = ",") {
1433
	$list = implode($separator, array_slice($list, 0, $count));
1434
	if (count($list) < $count) {
1435
		$list .= ".";
1436
	} else {
1437
		$list .= "...";
1438
	}
1439
	return $list;
1440
}
1441

    
1442
/* DHCP enabled on any interfaces? */
1443
function is_dhcp_server_enabled() {
1444
	global $config;
1445

    
1446
	if (!is_array($config['dhcpd'])) {
1447
		return false;
1448
	}
1449

    
1450
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1451
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1452
			return true;
1453
		}
1454
	}
1455

    
1456
	return false;
1457
}
1458

    
1459
/* DHCP enabled on any interfaces? */
1460
function is_dhcpv6_server_enabled() {
1461
	global $config;
1462

    
1463
	if (is_array($config['interfaces'])) {
1464
		foreach ($config['interfaces'] as $ifcfg) {
1465
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1466
				return true;
1467
			}
1468
		}
1469
	}
1470

    
1471
	if (!is_array($config['dhcpdv6'])) {
1472
		return false;
1473
	}
1474

    
1475
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1476
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1477
			return true;
1478
		}
1479
	}
1480

    
1481
	return false;
1482
}
1483

    
1484
/* radvd enabled on any interfaces? */
1485
function is_radvd_enabled() {
1486
	global $config;
1487

    
1488
	if (!is_array($config['dhcpdv6'])) {
1489
		$config['dhcpdv6'] = array();
1490
	}
1491

    
1492
	$dhcpdv6cfg = $config['dhcpdv6'];
1493
	$Iflist = get_configured_interface_list();
1494

    
1495
	/* handle manually configured DHCP6 server settings first */
1496
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1497
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1498
			continue;
1499
		}
1500

    
1501
		if (!isset($dhcpv6ifconf['ramode'])) {
1502
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1503
		}
1504

    
1505
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1506
			continue;
1507
		}
1508

    
1509
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1510
		if (!is_ipaddrv6($ifcfgipv6)) {
1511
			continue;
1512
		}
1513

    
1514
		return true;
1515
	}
1516

    
1517
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1518
	foreach ($Iflist as $if => $ifdescr) {
1519
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1520
			continue;
1521
		}
1522
		if (!isset($config['interfaces'][$if]['enable'])) {
1523
			continue;
1524
		}
1525

    
1526
		$ifcfgipv6 = get_interface_ipv6($if);
1527
		if (!is_ipaddrv6($ifcfgipv6)) {
1528
			continue;
1529
		}
1530

    
1531
		$ifcfgsnv6 = get_interface_subnetv6($if);
1532
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1533

    
1534
		if (!is_ipaddrv6($subnetv6)) {
1535
			continue;
1536
		}
1537

    
1538
		return true;
1539
	}
1540

    
1541
	return false;
1542
}
1543

    
1544
/* Any PPPoE servers enabled? */
1545
function is_pppoe_server_enabled() {
1546
	global $config;
1547

    
1548
	$pppoeenable = false;
1549

    
1550
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1551
		return false;
1552
	}
1553

    
1554
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1555
		if ($pppoes['mode'] == 'server') {
1556
			$pppoeenable = true;
1557
		}
1558
	}
1559

    
1560
	return $pppoeenable;
1561
}
1562

    
1563
/* Optional arg forces hh:mm:ss without days */
1564
function convert_seconds_to_dhms($sec, $showhoursonly = false) {
1565
	if (!is_numericint($sec)) {
1566
		return '-';
1567
	}
1568
	// FIXME: When we move to PHP 7 we can use "intdiv($sec % X, Y)" etc
1569
	list($d, $h, $m, $s) = array(	(int)($showhoursonly ? 0 : $sec/86400),
1570
					(int)(($showhoursonly ? $sec : $sec % 86400)/3600),
1571
					(int)(($sec % 3600)/60),
1572
					$sec % 60
1573
				);
1574
	return ($d > 0 ? $d . 'd ' : '') . sprintf('%02d:%02d:%02d', $h, $m, $s);
1575
}
1576

    
1577
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1578

    
1579
function get_ppp_uptime($port) {
1580
	if (file_exists("/conf/{$port}.log")) {
1581
		$saved_time = file_get_contents("/conf/{$port}.log");
1582
		$uptime_data = explode("\n", $saved_time);
1583
		$sec = 0;
1584
		foreach ($uptime_data as $upt) {
1585
			$sec += substr($upt, 1 + strpos($upt, " "));
1586
		}
1587
		return convert_seconds_to_dhms($sec);
1588
	} else {
1589
		$total_time = gettext("No history data found!");
1590
		return $total_time;
1591
	}
1592
}
1593

    
1594
//returns interface information
1595
function get_interface_info($ifdescr) {
1596
	global $config, $g;
1597

    
1598
	$ifinfo = array();
1599
	if (empty($config['interfaces'][$ifdescr])) {
1600
		return;
1601
	}
1602
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1603
	$ifinfo['enable'] = isset($config['interfaces'][$ifdescr]['enable']);
1604
	$ifinfo['if'] = get_real_interface($ifdescr);
1605

    
1606
	$chkif = $ifinfo['if'];
1607
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1608
	$ifinfo['status'] = $ifinfotmp['status'];
1609
	if (empty($ifinfo['status'])) {
1610
		$ifinfo['status'] = "down";
1611
	}
1612
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1613
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1614
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1615
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1616
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1617
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1618
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1619
	if (isset($ifinfotmp['link0'])) {
1620
		$link0 = "down";
1621
	}
1622
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1623
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1624
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1625
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1626
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1627
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1628

    
1629
	/* Use pfctl for non wrapping 64 bit counters */
1630
	/* Pass */
1631
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1632
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1633
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1634
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1635
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1636
	$in4_pass = $pf_in4_pass[5];
1637
	$out4_pass = $pf_out4_pass[5];
1638
	$in4_pass_packets = $pf_in4_pass[3];
1639
	$out4_pass_packets = $pf_out4_pass[3];
1640
	$in6_pass = $pf_in6_pass[5];
1641
	$out6_pass = $pf_out6_pass[5];
1642
	$in6_pass_packets = $pf_in6_pass[3];
1643
	$out6_pass_packets = $pf_out6_pass[3];
1644
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1645
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1646
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1647
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1648

    
1649
	/* Block */
1650
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1651
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1652
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1653
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1654
	$in4_block = $pf_in4_block[5];
1655
	$out4_block = $pf_out4_block[5];
1656
	$in4_block_packets = $pf_in4_block[3];
1657
	$out4_block_packets = $pf_out4_block[3];
1658
	$in6_block = $pf_in6_block[5];
1659
	$out6_block = $pf_out6_block[5];
1660
	$in6_block_packets = $pf_in6_block[3];
1661
	$out6_block_packets = $pf_out6_block[3];
1662
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1663
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1664
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1665
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1666

    
1667
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1668
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1669
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1670
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1671

    
1672
	$ifconfiginfo = "";
1673
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1674
	switch ($link_type) {
1675
		/* DHCP? -> see if dhclient is up */
1676
		case "dhcp":
1677
			/* see if dhclient is up */
1678
			if (find_dhclient_process($ifinfo['if']) != 0) {
1679
				$ifinfo['dhcplink'] = "up";
1680
			} else {
1681
				$ifinfo['dhcplink'] = "down";
1682
			}
1683

    
1684
			break;
1685
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1686
		case "pppoe":
1687
		case "pptp":
1688
		case "l2tp":
1689
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1690
				/* get PPPoE link status for dial on demand */
1691
				$ifinfo["{$link_type}link"] = "up";
1692
			} else {
1693
				$ifinfo["{$link_type}link"] = "down";
1694
			}
1695

    
1696
			break;
1697
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1698
		case "ppp":
1699
			if ($ifinfo['status'] == "up") {
1700
				$ifinfo['ppplink'] = "up";
1701
			} else {
1702
				$ifinfo['ppplink'] = "down" ;
1703
			}
1704

    
1705
			if (empty($ifinfo['status'])) {
1706
				$ifinfo['status'] = "down";
1707
			}
1708

    
1709
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1710
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1711
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1712
						break;
1713
					}
1714
				}
1715
			}
1716
			$dev = $ppp['ports'];
1717
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1718
				break;
1719
			}
1720
			if (!file_exists($dev)) {
1721
				$ifinfo['nodevice'] = 1;
1722
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1723
			}
1724

    
1725
			$usbmodemoutput = array();
1726
			exec("/usr/sbin/usbconfig", $usbmodemoutput);
1727
			$mondev = "{$g['tmp_path']}/3gstats.{$ifdescr}";
1728
			if (file_exists($mondev)) {
1729
				$cellstats = file($mondev);
1730
				/* skip header */
1731
				$a_cellstats = explode(",", $cellstats[1]);
1732
				if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1733
					$ifinfo['cell_rssi'] = huawei_rssi_to_string($a_cellstats[1]);
1734
					$ifinfo['cell_mode'] = huawei_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1735
					$ifinfo['cell_simstate'] = huawei_simstate_to_string($a_cellstats[10]);
1736
					$ifinfo['cell_service'] = huawei_service_to_string(trim($a_cellstats[11]));
1737
				}
1738
				if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1739
					$ifinfo['cell_rssi'] = zte_rssi_to_string($a_cellstats[1]);
1740
					$ifinfo['cell_mode'] = zte_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1741
					$ifinfo['cell_simstate'] = zte_simstate_to_string($a_cellstats[10]);
1742
					$ifinfo['cell_service'] = zte_service_to_string(trim($a_cellstats[11]));
1743
				}
1744
				$ifinfo['cell_upstream'] = $a_cellstats[4];
1745
				$ifinfo['cell_downstream'] = trim($a_cellstats[5]);
1746
				$ifinfo['cell_sent'] = $a_cellstats[6];
1747
				$ifinfo['cell_received'] = trim($a_cellstats[7]);
1748
				$ifinfo['cell_bwupstream'] = $a_cellstats[8];
1749
				$ifinfo['cell_bwdownstream'] = trim($a_cellstats[9]);
1750
			}
1751
			// Calculate cumulative uptime for PPP link. Useful for connections that have per minute/hour contracts so you don't go over!
1752
			if (isset($ppp['uptime'])) {
1753
				$ifinfo['ppp_uptime_accumulated'] = "(".get_ppp_uptime($ifinfo['if']).")";
1754
			}
1755
			break;
1756
		default:
1757
			break;
1758
	}
1759

    
1760
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1761
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1762
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1763
	}
1764

    
1765
	if ($ifinfo['status'] == "up") {
1766
		/* try to determine media with ifconfig */
1767
		unset($ifconfiginfo);
1768
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1769
		$wifconfiginfo = array();
1770
		if (is_interface_wireless($ifdescr)) {
1771
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1772
			array_shift($wifconfiginfo);
1773
		}
1774
		$matches = "";
1775
		foreach ($ifconfiginfo as $ici) {
1776

    
1777
			/* don't list media/speed for wireless cards, as it always
1778
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1779
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1780
				$ifinfo['media'] = $matches[1];
1781
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1782
				$ifinfo['media'] = $matches[1];
1783
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1784
				$ifinfo['media'] = $matches[1];
1785
			}
1786

    
1787
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1788
				if ($matches[1] != "active") {
1789
					$ifinfo['status'] = $matches[1];
1790
				}
1791
				if ($ifinfo['status'] == gettext("running")) {
1792
					$ifinfo['status'] = gettext("up");
1793
				}
1794
			}
1795
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1796
				$ifinfo['channel'] = $matches[1];
1797
			}
1798
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1799
				if ($matches[1][0] == '"') {
1800
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1801
				}
1802
				else {
1803
					$ifinfo['ssid'] = $matches[1];
1804
				}
1805
			}
1806
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1807
				$ifinfo['laggproto'] = $matches[1];
1808
			}
1809
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1810
				$ifinfo['laggport'][] = $matches[1];
1811
			}
1812
		}
1813
		foreach ($wifconfiginfo as $ici) {
1814
			$elements = preg_split("/[ ]+/i", $ici);
1815
			if ($elements[0] != "") {
1816
				$ifinfo['bssid'] = $elements[0];
1817
			}
1818
			if ($elements[3] != "") {
1819
				$ifinfo['rate'] = $elements[3];
1820
			}
1821
			if ($elements[4] != "") {
1822
				$ifinfo['rssi'] = $elements[4];
1823
			}
1824
		}
1825
		/* lookup the gateway */
1826
		if (interface_has_gateway($ifdescr)) {
1827
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1828
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1829
		}
1830
	}
1831

    
1832
	$bridge = "";
1833
	$bridge = link_interface_to_bridge($ifdescr);
1834
	if ($bridge) {
1835
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1836
		if (stristr($bridge_text, "blocking") <> false) {
1837
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1838
			$ifinfo['bridgeint'] = $bridge;
1839
		} else if (stristr($bridge_text, "learning") <> false) {
1840
			$ifinfo['bridge'] = gettext("learning");
1841
			$ifinfo['bridgeint'] = $bridge;
1842
		} else if (stristr($bridge_text, "forwarding") <> false) {
1843
			$ifinfo['bridge'] = gettext("forwarding");
1844
			$ifinfo['bridgeint'] = $bridge;
1845
		}
1846
	}
1847

    
1848
	return $ifinfo;
1849
}
1850

    
1851
//returns cpu speed of processor. Good for determining capabilities of machine
1852
function get_cpu_speed() {
1853
	return get_single_sysctl("hw.clockrate");
1854
}
1855

    
1856
function get_uptime_sec() {
1857
	$boottime = "";
1858
	$matches = "";
1859
	$boottime = get_single_sysctl("kern.boottime");
1860
	preg_match("/sec = (\d+)/", $boottime, $matches);
1861
	$boottime = $matches[1];
1862
	if (intval($boottime) == 0) {
1863
		return 0;
1864
	}
1865

    
1866
	$uptime = time() - $boottime;
1867
	return $uptime;
1868
}
1869

    
1870
function resolve_host_addresses($host, $recordtypes = array(DNS_A, DNS_AAAA, DNS_CNAME), $index = true) {
1871
	$dnsresult = array();
1872
	$resolved = array();
1873
	$errreporting = error_reporting();
1874
	error_reporting($errreporting & ~E_WARNING);// dns_get_record throws a warning if nothing is resolved..
1875
	foreach ($recordtypes as $recordtype) {
1876
		$tmp = dns_get_record($host, $recordtype);
1877
		if (is_array($tmp)) {
1878
			$dnsresult = array_merge($dnsresult, $tmp);
1879
		}
1880
	}
1881
	error_reporting($errreporting);// restore original php warning/error settings.
1882
	foreach ($dnsresult as $item) {
1883
		$newitem = array();
1884
		$newitem['type'] = $item['type'];
1885
		switch ($item['type']) {
1886
			case 'CNAME':
1887
				$newitem['data'] = $item['target'];
1888
				$resolved[] = $newitem;
1889
				break;
1890
			case 'A':
1891
				$newitem['data'] = $item['ip'];
1892
				$resolved[] = $newitem;
1893
				break;
1894
			case 'AAAA':
1895
				$newitem['data'] = $item['ipv6'];
1896
				$resolved[] = $newitem;
1897
				break;
1898
		}
1899
	}
1900
	if ($index == false) {
1901
		foreach ($resolved as $res) {
1902
			$noind[] = $res['data'];
1903
		}
1904
		$resolved = $noind;
1905
	}
1906
	return $resolved;
1907
}
1908

    
1909
function add_hostname_to_watch($hostname) {
1910
	if (!is_dir("/var/db/dnscache")) {
1911
		mkdir("/var/db/dnscache");
1912
	}
1913
	$result = array();
1914
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1915
		$contents = "";
1916
		$domips = resolve_host_addresses($hostname, array(DNS_A), false);
1917
		if (!empty($domips)) {
1918
			foreach ($domips as $ip) {
1919
				$contents .= "$ip\n";
1920
			}
1921
		}
1922
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1923
		/* Remove empty elements */
1924
		$result = array_filter(explode("\n", $contents), 'strlen');
1925
	}
1926
	return $result;
1927
}
1928

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

    
1933
function pfsense_default_state_size() {
1934
	/* get system memory amount */
1935
	$memory = get_memory();
1936
	$physmem = $memory[0];
1937
	/* Be cautious and only allocate 10% of system memory to the state table */
1938
	$max_states = (int) ($physmem/10)*1000;
1939
	return $max_states;
1940
}
1941

    
1942
function pfsense_default_tables_size() {
1943
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1944
	return $current;
1945
}
1946

    
1947
function pfsense_default_table_entries_size() {
1948
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1949
	return (trim($current));
1950
}
1951

    
1952
/* Compare the current hostname DNS to the DNS cache we made
1953
 * if it has changed we return the old records
1954
 * if no change we return false */
1955
function compare_hostname_to_dnscache($hostname) {
1956
	if (!is_dir("/var/db/dnscache")) {
1957
		mkdir("/var/db/dnscache");
1958
	}
1959
	$hostname = trim($hostname);
1960
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1961
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1962
	} else {
1963
		$oldcontents = "";
1964
	}
1965
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1966
		$contents = "";
1967
		$domips = resolve_host_addresses($hostname, array(DNS_A), false);
1968
		if (!empty($domips)) {
1969
			foreach ($domips as $ip) {
1970
				$contents .= "$ip\n";
1971
			}
1972
		}
1973
	}
1974

    
1975
	if (trim($oldcontents) != trim($contents)) {
1976
		if ($g['debug']) {
1977
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1978
		}
1979
		return ($oldcontents);
1980
	} else {
1981
		return false;
1982
	}
1983
}
1984

    
1985
/*
1986
 * load_crypto() - Load crypto modules if enabled in config.
1987
 */
1988
function load_crypto() {
1989
	global $config, $g;
1990
	$crypto_modules = array('aesni', 'cryptodev');
1991

    
1992
	$enabled_modules = explode('_', $config['system']['crypto_hardware']);
1993

    
1994
	foreach ($enabled_modules as $enmod) {
1995
		if (empty($enmod) || !in_array($enmod, $crypto_modules)) {
1996
			continue;
1997
		}
1998
		if (!is_module_loaded($enmod)) {
1999
			log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $enmod));
2000
			mwexec("/sbin/kldload " . escapeshellarg($enmod));
2001
		}
2002
	}
2003
}
2004

    
2005
/*
2006
 * load_thermal_hardware() - Load temperature monitor kernel module
2007
 */
2008
function load_thermal_hardware() {
2009
	global $config, $g;
2010
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
2011

    
2012
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
2013
		return false;
2014
	}
2015

    
2016
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
2017
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
2018
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
2019
	}
2020
}
2021

    
2022
/****f* pfsense-utils/isvm
2023
 * NAME
2024
 *   isvm
2025
 * INPUTS
2026
 *	none
2027
 * RESULT
2028
 *   returns true if machine is running under a virtual environment
2029
 ******/
2030
function isvm() {
2031
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
2032
	$_gb = exec('/bin/kenv -q smbios.system.product 2>/dev/null', $output, $rc);
2033

    
2034
	if ($rc != 0 || !isset($output[0])) {
2035
		return false;
2036
	}
2037

    
2038
	foreach ($virtualenvs as $virtualenv) {
2039
		if (stripos($output[0], $virtualenv) !== false) {
2040
			return true;
2041
		}
2042
	}
2043

    
2044
	return false;
2045
}
2046

    
2047
function get_freebsd_version() {
2048
	$version = explode(".", php_uname("r"));
2049
	return $version[0];
2050
}
2051

    
2052
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
2053
	global $config, $g;
2054

    
2055
	$fp = fopen($destination, "wb");
2056

    
2057
	if (!$fp) {
2058
		return false;
2059
	}
2060

    
2061
	$ch = curl_init();
2062
	curl_setopt($ch, CURLOPT_URL, $url);
2063
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
2064
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2065
	curl_setopt($ch, CURLOPT_FILE, $fp);
2066
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2067
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2068
	curl_setopt($ch, CURLOPT_HEADER, false);
2069
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2070
	if (!isset($config['system']['do_not_send_uniqueid'])) {
2071
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
2072
	} else {
2073
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2074
	}
2075

    
2076
	if (!empty($config['system']['proxyurl'])) {
2077
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2078
		if (!empty($config['system']['proxyport'])) {
2079
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2080
		}
2081
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2082
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2083
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2084
		}
2085
	}
2086

    
2087
	@curl_exec($ch);
2088
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2089
	fclose($fp);
2090
	curl_close($ch);
2091
	if ($http_code == 200) {
2092
		return true;
2093
	} else {
2094
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2095
		unlink_if_exists($destination);
2096
		return false;
2097
	}
2098
}
2099

    
2100
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
2101
	global $config, $g;
2102
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
2103
	$file_size = 1;
2104
	$downloaded = 1;
2105
	$first_progress_update = TRUE;
2106
	/* open destination file */
2107
	$fout = fopen($destination, "wb");
2108

    
2109
	if (!$fout) {
2110
		return false;
2111
	}
2112
	/*
2113
	 *      Originally by Author: Keyvan Minoukadeh
2114
	 *      Modified by Scott Ullrich to return Content-Length size
2115
	 */
2116
	$ch = curl_init();
2117
	curl_setopt($ch, CURLOPT_URL, $url);
2118
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
2119
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2120
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
2121
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2122
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
2123
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
2124
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2125
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2126
	if (!isset($config['system']['do_not_send_uniqueid'])) {
2127
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
2128
	} else {
2129
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2130
	}
2131

    
2132
	if (!empty($config['system']['proxyurl'])) {
2133
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2134
		if (!empty($config['system']['proxyport'])) {
2135
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2136
		}
2137
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2138
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2139
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2140
		}
2141
	}
2142

    
2143
	@curl_exec($ch);
2144
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2145
	fclose($fout);
2146
	curl_close($ch);
2147
	if ($http_code == 200) {
2148
		return true;
2149
	} else {
2150
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2151
		unlink_if_exists($destination);
2152
		return false;
2153
	}
2154
}
2155

    
2156
function read_header($ch, $string) {
2157
	global $file_size, $fout;
2158
	$length = strlen($string);
2159
	$regs = "";
2160
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
2161
	if ($regs[2] <> "") {
2162
		$file_size = intval($regs[2]);
2163
	}
2164
	ob_flush();
2165
	return $length;
2166
}
2167

    
2168
function read_body($ch, $string) {
2169
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
2170
	global $pkg_interface;
2171
	$length = strlen($string);
2172
	$downloaded += intval($length);
2173
	if ($file_size > 0) {
2174
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
2175
		$downloadProgress = 100 - $downloadProgress;
2176
	} else {
2177
		$downloadProgress = 0;
2178
	}
2179
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
2180
		if ($sendto == "status") {
2181
			if ($pkg_interface == "console") {
2182
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2183
					$tostatus = $static_status . $downloadProgress . "%";
2184
					if ($downloadProgress == 100) {
2185
						$tostatus = $tostatus . "\r";
2186
					}
2187
					update_status($tostatus);
2188
				}
2189
			} else {
2190
				$tostatus = $static_status . $downloadProgress . "%";
2191
				update_status($tostatus);
2192
			}
2193
		} else {
2194
			if ($pkg_interface == "console") {
2195
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2196
					$tooutput = $static_output . $downloadProgress . "%";
2197
					if ($downloadProgress == 100) {
2198
						$tooutput = $tooutput . "\r";
2199
					}
2200
					update_output_window($tooutput);
2201
				}
2202
			} else {
2203
				$tooutput = $static_output . $downloadProgress . "%";
2204
				update_output_window($tooutput);
2205
			}
2206
		}
2207
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
2208
			update_progress_bar($downloadProgress, $first_progress_update);
2209
			$first_progress_update = FALSE;
2210
		}
2211
		$lastseen = $downloadProgress;
2212
	}
2213
	if ($fout) {
2214
		fwrite($fout, $string);
2215
	}
2216
	ob_flush();
2217
	return $length;
2218
}
2219

    
2220
/*
2221
 *   update_output_window: update bottom textarea dynamically.
2222
 */
2223
function update_output_window($text) {
2224
	global $pkg_interface;
2225
	$log = preg_replace("/\n/", "\\n", $text);
2226
	if ($pkg_interface != "console") {
2227
?>
2228
<script type="text/javascript">
2229
//<![CDATA[
2230
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
2231
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
2232
//]]>
2233
</script>
2234
<?php
2235
	}
2236
	/* ensure that contents are written out */
2237
	ob_flush();
2238
}
2239

    
2240
/*
2241
 *   update_status: update top textarea dynamically.
2242
 */
2243
function update_status($status) {
2244
	global $pkg_interface;
2245

    
2246
	if ($pkg_interface == "console") {
2247
		print ("{$status}");
2248
	}
2249

    
2250
	/* ensure that contents are written out */
2251
	ob_flush();
2252
}
2253

    
2254
/*
2255
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
2256
 */
2257
function update_progress_bar($percent, $first_time) {
2258
	global $pkg_interface;
2259
	if ($percent > 100) {
2260
		$percent = 1;
2261
	}
2262
	if ($pkg_interface <> "console") {
2263
		echo '<script type="text/javascript">';
2264
		echo "\n//<![CDATA[\n";
2265
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
2266
		echo "\n//]]>\n";
2267
		echo '</script>';
2268
	} else {
2269
		if (!($first_time)) {
2270
			echo "\x08\x08\x08\x08\x08";
2271
		}
2272
		echo sprintf("%4d%%", $percent);
2273
	}
2274
}
2275

    
2276
function update_alias_name($new_alias_name, $orig_alias_name) {
2277
	if (!$orig_alias_name) {
2278
		return;
2279
	}
2280

    
2281
	// Firewall rules
2282
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2283
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2284
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2285
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2286
	// NAT Rules
2287
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2288
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2289
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2290
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2291
	update_alias_names_upon_change(array('nat', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2292
	update_alias_names_upon_change(array('nat', 'rule'), array('local-port'), $new_alias_name, $orig_alias_name);
2293
	// NAT 1:1 Rules
2294
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('external'), $new_alias_name, $orig_alias_name);
2295
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2296
	update_alias_names_upon_change(array('nat', 'onetoone'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2297
	// NAT Outbound Rules
2298
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('source', 'network'), $new_alias_name, $orig_alias_name);
2299
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('sourceport'), $new_alias_name, $orig_alias_name);
2300
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2301
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('dstport'), $new_alias_name, $orig_alias_name);
2302
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2303
	// Alias in an alias
2304
	update_alias_names_upon_change(array('aliases', 'alias'), array('address'), $new_alias_name, $orig_alias_name);
2305
}
2306

    
2307
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2308
	global $g, $config, $pconfig, $debug;
2309
	if (!$origname) {
2310
		return;
2311
	}
2312

    
2313
	$sectionref = &$config;
2314
	foreach ($section as $sectionname) {
2315
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2316
			$sectionref = &$sectionref[$sectionname];
2317
		} else {
2318
			return;
2319
		}
2320
	}
2321

    
2322
	if ($debug) {
2323
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2324
		fwrite($fd, print_r($pconfig, true));
2325
	}
2326

    
2327
	if (is_array($sectionref)) {
2328
		foreach ($sectionref as $itemkey => $item) {
2329
			if ($debug) {
2330
				fwrite($fd, "$itemkey\n");
2331
			}
2332

    
2333
			$fieldfound = true;
2334
			$fieldref = &$sectionref[$itemkey];
2335
			foreach ($field as $fieldname) {
2336
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2337
					$fieldref = &$fieldref[$fieldname];
2338
				} else {
2339
					$fieldfound = false;
2340
					break;
2341
				}
2342
			}
2343
			if ($fieldfound && $fieldref == $origname) {
2344
				if ($debug) {
2345
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2346
				}
2347
				$fieldref = $new_alias_name;
2348
			}
2349
		}
2350
	}
2351

    
2352
	if ($debug) {
2353
		fclose($fd);
2354
	}
2355

    
2356
}
2357

    
2358
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2359
	/*
2360
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2361
	 * $type = if set to 'url' then subnets and ips will be returned,
2362
	 *         if set to 'url_ports' port-ranges and ports will be returned
2363
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2364
	 *
2365
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2366
	 */
2367

    
2368
	if (!file_exists($filename)) {
2369
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2370
		return null;
2371
	}
2372

    
2373
	if (filesize($filename) == 0) {
2374
		log_error(sprintf(gettext("Could not process empty file from alias: %s"), $filename));
2375
		return null;
2376
	}
2377
	$fd = @fopen($filename, 'r');
2378
	if (!$fd) {
2379
		log_error(sprintf(gettext("Could not process aliases from alias: %s"), $filename));
2380
		return null;
2381
	}
2382
	$items = array();
2383
	$comments = array();
2384
	/* NOTE: fgetss() is not a typo RTFM before being smart */
2385
	while (($fc = fgetss($fd)) !== FALSE) {
2386
		$tmp = trim($fc, " \t\n\r");
2387
		if (empty($tmp)) {
2388
			continue;
2389
		}
2390
		if (($kflc) && (strpos($tmp, '#') === 0)) {	// Keep Full Line Comments (lines beginning with #).
2391
			$comments[] = $tmp;
2392
		} else {
2393
			$tmp_str = strstr($tmp, '#', true);
2394
			if (!empty($tmp_str)) {
2395
				$tmp = $tmp_str;
2396
			}
2397
			$tmp_str = strstr($tmp, ' ', true);
2398
			if (!empty($tmp_str)) {
2399
				$tmp = $tmp_str;
2400
			}
2401
			switch ($type) {
2402
				case "url":
2403
				case "urltable":
2404
					if (is_ipaddr($tmp) || is_subnet($tmp)) {
2405
						$items[] = $tmp;
2406
						break;
2407
					}
2408
					if (is_fqdn($tmp)) {
2409
						$results = resolve_host_addresses($tmp, array(DNS_A, DNS_AAAA), false);
2410
						if (!empty($results)) {
2411
							foreach ($results as $ip) {
2412
								if (is_ipaddr($ip)) {
2413
									$items[] = $ip;
2414
								}
2415
							}
2416
						}
2417
					}
2418
					break;
2419
				case "url_ports":
2420
				case "urltable_ports":
2421
					if (is_port_or_range($tmp)) {
2422
						$items[] = $tmp;
2423
					}
2424
					break;
2425
				default:
2426
					/* unknown type */
2427
					break;
2428
				}
2429
			if (count($items) == $max_items) {
2430
				break;
2431
			}
2432
		}
2433
	}
2434
	fclose($fd);
2435
	return array_merge($comments, $items);
2436
}
2437

    
2438
function update_alias_url_data() {
2439
	global $config, $g;
2440

    
2441
	$updated = false;
2442

    
2443
	/* item is a url type */
2444
	$lockkey = lock('aliasurl');
2445
	if (is_array($config['aliases']['alias'])) {
2446
		foreach ($config['aliases']['alias'] as $x => $alias) {
2447
			if (empty($alias['aliasurl'])) {
2448
				continue;
2449
			}
2450

    
2451
			$address = null;
2452
			foreach ($alias['aliasurl'] as $alias_url) {
2453
				/* fetch down and add in */
2454
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2455
				unlink($temp_filename);
2456
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2457
				mkdir($temp_filename);
2458
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2459
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2460
					continue;
2461
				}
2462

    
2463
				/* if the item is tar gzipped then extract */
2464
				if (stripos($alias_url, '.tgz')) {
2465
					if (!process_alias_tgz($temp_filename)) {
2466
						continue;
2467
					}
2468
				}
2469
				if (file_exists("{$temp_filename}/aliases")) {
2470
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2471
					mwexec("/bin/rm -rf {$temp_filename}");
2472
				}
2473
			}
2474
			if ($address != null) {
2475
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2476
				$updated = true;
2477
			}
2478
		}
2479
	}
2480
	unlock($lockkey);
2481

    
2482
	/* Report status to callers as well */
2483
	return $updated;
2484
}
2485

    
2486
function process_alias_tgz($temp_filename) {
2487
	if (!file_exists('/usr/bin/tar')) {
2488
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2489
		return false;
2490
	}
2491
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2492
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2493
	unlink("{$temp_filename}/aliases.tgz");
2494
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2495
	/* foreach through all extracted files and build up aliases file */
2496
	$fd = @fopen("{$temp_filename}/aliases", "w");
2497
	if (!$fd) {
2498
		log_error(sprintf(gettext("Could not open %s/aliases for writing!"), $temp_filename));
2499
		return false;
2500
	}
2501
	foreach ($files_to_process as $f2p) {
2502
		$tmpfd = @fopen($f2p, 'r');
2503
		if (!$tmpfd) {
2504
			log_error(sprintf(gettext('The following file could not be read %1$s from %2$s'), $f2p, $temp_filename));
2505
			continue;
2506
		}
2507
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2508
			fwrite($fd, $tmpbuf);
2509
		}
2510
		fclose($tmpfd);
2511
		unlink($f2p);
2512
	}
2513
	fclose($fd);
2514
	unset($tmpbuf);
2515

    
2516
	return true;
2517
}
2518

    
2519
function version_compare_dates($a, $b) {
2520
	$a_time = strtotime($a);
2521
	$b_time = strtotime($b);
2522

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

    
2574
	foreach ($a_arr as $n => $val) {
2575
		if (array_key_exists($n, $b_arr)) {
2576
			// So far so good, both have values at this minor version level. Compare.
2577
			if ($val > $b_arr[$n]) {
2578
				return 1;
2579
			} elseif ($val < $b_arr[$n]) {
2580
				return -1;
2581
			}
2582
		} else {
2583
			// a is greater, since b doesn't have any minor version here.
2584
			return 1;
2585
		}
2586
	}
2587
	if (count($b_arr) > count($a_arr)) {
2588
		// b is longer than a, so it must be greater.
2589
		return -1;
2590
	} else {
2591
		// Both a and b are of equal length and value.
2592
		return 0;
2593
	}
2594
}
2595
function pfs_version_compare($cur_time, $cur_text, $remote) {
2596
	// First try date compare
2597
	$v = version_compare_dates($cur_time, $remote);
2598
	if ($v === FALSE) {
2599
		// If that fails, try to compare by string
2600
		// Before anything else, simply test if the strings are equal
2601
		if (($cur_text == $remote) || ($cur_time == $remote)) {
2602
			return 0;
2603
		}
2604
		list($cur_num, $cur_str) = explode('-', $cur_text);
2605
		list($rem_num, $rem_str) = explode('-', $remote);
2606

    
2607
		// First try to compare the numeric parts of the version string.
2608
		$v = version_compare_numeric($cur_num, $rem_num);
2609

    
2610
		// If the numeric parts are the same, compare the string parts.
2611
		if ($v == 0) {
2612
			return version_compare_string($cur_str, $rem_str);
2613
		}
2614
	}
2615
	return $v;
2616
}
2617
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2618
	global $g, $config;
2619

    
2620
	$urltable_prefix = "/var/db/aliastables/";
2621
	$urltable_filename = $urltable_prefix . $name . ".txt";
2622
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2623

    
2624
	// Make the aliases directory if it doesn't exist
2625
	if (!file_exists($urltable_prefix)) {
2626
		mkdir($urltable_prefix);
2627
	} elseif (!is_dir($urltable_prefix)) {
2628
		unlink($urltable_prefix);
2629
		mkdir($urltable_prefix);
2630
	}
2631

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

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

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

    
2646
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2647
			if ($type == "urltable_ports") {
2648
				$parsed_contents = group_ports($parsed_contents, true);
2649
			}
2650
			if (is_array($parsed_contents)) {
2651
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2652
			} else {
2653
				touch($urltable_filename);
2654
			}
2655

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

    
2662
			unlink_if_exists($tmp_urltable_filename);
2663
		} else {
2664
			if (!$validateonly) {
2665
				touch($urltable_filename);
2666
			}
2667
			return false;
2668
		}
2669
		return true;
2670
	} else {
2671
		// File exists, and it doesn't need to be updated.
2672
		return -1;
2673
	}
2674
}
2675

    
2676
function get_include_contents($filename) {
2677
	if (is_file($filename)) {
2678
		ob_start();
2679
		include $filename;
2680
		$contents = ob_get_contents();
2681
		ob_end_clean();
2682
		return $contents;
2683
	}
2684
	return false;
2685
}
2686

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

    
2799
function get_country_name($country_code = "ALL") {
2800
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2801
		return "";
2802
	}
2803

    
2804
	$country_names_xml = "/usr/local/share/pfSense/iso_3166-1_list_en.xml";
2805
	$country_names_contents = file_get_contents($country_names_xml);
2806
	$country_names = xml2array($country_names_contents);
2807

    
2808
	if ($country_code == "ALL") {
2809
		$country_list = array();
2810
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2811
			$country_list[] = array(
2812
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2813
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2814
		}
2815
		return $country_list;
2816
	}
2817

    
2818
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2819
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2820
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2821
		}
2822
	}
2823
	return "";
2824
}
2825

    
2826
/* Return the list of country codes to be used on CAs and certs */
2827
function get_cert_country_codes() {
2828
	$countries = get_country_name();
2829

    
2830
	$country_codes = array();
2831
	foreach ($countries as $country) {
2832
		$country_codes[$country['code']] = $country['code'];
2833
	}
2834
	ksort($country_codes);
2835

    
2836
	/* Preserve historical order: None, US, CA, other countries */
2837
	$first_items[''] = gettext("None");
2838
	$first_items['US'] = $country_codes['US'];
2839
	$first_items['CA'] = $country_codes['CA'];
2840
	unset($country_codes['US']);
2841
	unset($country_codes['CA']);
2842

    
2843
	return array_merge($first_items, $country_codes);
2844
}
2845

    
2846
/* sort by interface only, retain the original order of rules that apply to
2847
   the same interface */
2848
function filter_rules_sort() {
2849
	global $config;
2850

    
2851
	init_config_arr(array('filter', 'rule'));
2852
	/* mark each rule with the sequence number (to retain the order while sorting) */
2853
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2854
		if (!is_array($config['filter']['rule'][$i])) {
2855
			$config['filter']['rule'][$i] = array();
2856
		}
2857
		$config['filter']['rule'][$i]['seq'] = $i;
2858
	}
2859

    
2860
	usort($config['filter']['rule'], "filter_rules_compare");
2861

    
2862
	/* strip the sequence numbers again */
2863
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2864
		unset($config['filter']['rule'][$i]['seq']);
2865
	}
2866
}
2867
function filter_rules_compare($a, $b) {
2868
	if (isset($a['floating']) && isset($b['floating'])) {
2869
		return $a['seq'] - $b['seq'];
2870
	} else if (isset($a['floating'])) {
2871
		return -1;
2872
	} else if (isset($b['floating'])) {
2873
		return 1;
2874
	} else if ($a['interface'] == $b['interface']) {
2875
		return $a['seq'] - $b['seq'];
2876
	} else {
2877
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2878
	}
2879
}
2880

    
2881
function generate_ipv6_from_mac($mac) {
2882
	$elements = explode(":", $mac);
2883
	if (count($elements) <> 6) {
2884
		return false;
2885
	}
2886

    
2887
	$i = 0;
2888
	$ipv6 = "fe80::";
2889
	foreach ($elements as $byte) {
2890
		if ($i == 0) {
2891
			$hexadecimal = substr($byte, 1, 2);
2892
			$bitmap = base_convert($hexadecimal, 16, 2);
2893
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2894
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2895
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2896
		}
2897
		$ipv6 .= $byte;
2898
		if ($i == 1) {
2899
			$ipv6 .= ":";
2900
		}
2901
		if ($i == 3) {
2902
			$ipv6 .= ":";
2903
		}
2904
		if ($i == 2) {
2905
			$ipv6 .= "ff:fe";
2906
		}
2907

    
2908
		$i++;
2909
	}
2910
	return $ipv6;
2911
}
2912

    
2913
/****f* pfsense-utils/load_mac_manufacturer_table
2914
 * NAME
2915
 *   load_mac_manufacturer_table
2916
 * INPUTS
2917
 *   none
2918
 * RESULT
2919
 *   returns associative array with MAC-Manufacturer pairs
2920
 ******/
2921
function load_mac_manufacturer_table() {
2922
	/* load MAC-Manufacture data from the file */
2923
	$macs = false;
2924
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2925
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2926
	}
2927
	if ($macs) {
2928
		foreach ($macs as $line) {
2929
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2930
				/* store values like this $mac_man['000C29']='VMware' */
2931
				$mac_man["$matches[1]"] = $matches[2];
2932
			}
2933
		}
2934
		return $mac_man;
2935
	} else {
2936
		return -1;
2937
	}
2938

    
2939
}
2940

    
2941
/****f* pfsense-utils/is_ipaddr_configured
2942
 * NAME
2943
 *   is_ipaddr_configured
2944
 * INPUTS
2945
 *   IP Address to check.
2946
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2947
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2948
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2949
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2950
 *     If check_subnets is true and cidrprefix is specified,
2951
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2952
 * RESULT
2953
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2954
*/
2955
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2956
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2957
		return true;
2958
	}
2959
	return false;
2960
}
2961

    
2962
/****f* pfsense-utils/where_is_ipaddr_configured
2963
 * NAME
2964
 *   where_is_ipaddr_configured
2965
 * INPUTS
2966
 *   IP Address to check.
2967
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2968
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2969
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2970
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2971
 *     If check_subnets is true and cidrprefix is specified,
2972
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2973
 * RESULT
2974
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2975
 *   If there are no matches then an empty array is returned.
2976
*/
2977
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2978
	global $config;
2979

    
2980
	$where_configured = array();
2981

    
2982
	$pos = strpos($ignore_if, '_virtualip');
2983
	if ($pos !== false) {
2984
		$ignore_vip_id = substr($ignore_if, $pos+10);
2985
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2986
	} else {
2987
		$ignore_vip_id = -1;
2988
		$ignore_vip_if = $ignore_if;
2989
	}
2990

    
2991
	$isipv6 = is_ipaddrv6($ipaddr);
2992

    
2993
	if ($isipv6) {
2994
		$ipaddr = text_to_compressed_ip6($ipaddr);
2995
	}
2996

    
2997
	if ($check_subnets) {
2998
		$cidrprefix = intval($cidrprefix);
2999
		if ($isipv6) {
3000
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
3001
				$cidrprefix = 128;
3002
			}
3003
		} else {
3004
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
3005
				$cidrprefix = 32;
3006
			}
3007
		}
3008
		$iflist = get_configured_interface_list();
3009
		foreach ($iflist as $if => $ifname) {
3010
			if ($ignore_if == $if) {
3011
				continue;
3012
			}
3013

    
3014
			if ($isipv6) {
3015
				$if_ipv6 = get_interface_ipv6($if);
3016
				$if_snbitsv6 = get_interface_subnetv6($if);
3017
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
3018
					$where_entry = array();
3019
					$where_entry['if'] = $if;
3020
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
3021
					$where_configured[] = $where_entry;
3022
				}
3023
			} else {
3024
				$if_ipv4 = get_interface_ip($if);
3025
				$if_snbitsv4 = get_interface_subnet($if);
3026
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
3027
					$where_entry = array();
3028
					$where_entry['if'] = $if;
3029
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
3030
					$where_configured[] = $where_entry;
3031
				}
3032
			}
3033
		}
3034
	} else {
3035
		if ($isipv6) {
3036
			$interface_list_ips = get_configured_ipv6_addresses();
3037
		} else {
3038
			$interface_list_ips = get_configured_ip_addresses();
3039
		}
3040

    
3041
		foreach ($interface_list_ips as $if => $ilips) {
3042
			if ($ignore_if == $if) {
3043
				continue;
3044
			}
3045
			if (strcasecmp($ipaddr, $ilips) == 0) {
3046
				$where_entry = array();
3047
				$where_entry['if'] = $if;
3048
				$where_entry['ip_or_subnet'] = $ilips;
3049
				$where_configured[] = $where_entry;
3050
			}
3051
		}
3052
	}
3053

    
3054
	if ($check_localip) {
3055
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, text_to_compressed_ip6($config['l2tp']['localip'])) == 0)) {
3056
			$where_entry = array();
3057
			$where_entry['if'] = 'l2tp';
3058
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
3059
			$where_configured[] = $where_entry;
3060
		}
3061
	}
3062

    
3063
	return $where_configured;
3064
}
3065

    
3066
/****f* pfsense-utils/pfSense_handle_custom_code
3067
 * NAME
3068
 *   pfSense_handle_custom_code
3069
 * INPUTS
3070
 *   directory name to process
3071
 * RESULT
3072
 *   globs the directory and includes the files
3073
 */
3074
function pfSense_handle_custom_code($src_dir) {
3075
	// Allow extending of the nat edit page and include custom input validation
3076
	if (is_dir("$src_dir")) {
3077
		$cf = glob($src_dir . "/*.inc");
3078
		foreach ($cf as $nf) {
3079
			if ($nf == "." || $nf == "..") {
3080
				continue;
3081
			}
3082
			// Include the extra handler
3083
			include_once("$nf");
3084
		}
3085
	}
3086
}
3087

    
3088
function set_language() {
3089
	global $config, $g;
3090

    
3091
	if (!empty($config['system']['language'])) {
3092
		$lang = $config['system']['language'];
3093
	} elseif (!empty($g['language'])) {
3094
		$lang = $g['language'];
3095
	}
3096
	$lang .= ".UTF-8";
3097

    
3098
	putenv("LANG={$lang}");
3099
	setlocale(LC_ALL, $lang);
3100
	textdomain("pfSense");
3101
	bindtextdomain("pfSense", "/usr/local/share/locale");
3102
	bind_textdomain_codeset("pfSense", $lang);
3103
}
3104

    
3105
function get_locale_list() {
3106
	$locales = array(
3107
		"bs" => gettext("Bosnian"),
3108
		"zh_CN" => gettext("Chinese"),
3109
		"zh_Hans_CN" => gettext("Chinese (Simplified, China)"),
3110
		"zh_Hans_HK" => gettext("Chinese (Simplified, Hong Kong SAR China)"),
3111
		"zh_Hant_TW" => gettext("Chinese (Traditional, Taiwan)"),
3112
		"nl" => gettext("Dutch"),
3113
		"en_US" => gettext("English"),
3114
		"fr" => gettext("French"),
3115
		"de_DE" => gettext("German (Germany)"),
3116
		"it" => gettext("Italian"),
3117
		"ko" => gettext("Korean"),
3118
		"nb" => gettext("Norwegian Bokmål"),
3119
		"pl" => gettext("Polish"),
3120
		"pt_PT" => gettext("Portuguese"),
3121
		"pt_BR" => gettext("Portuguese (Brazil)"),
3122
		"ru" => gettext("Russian"),
3123
		"es" => gettext("Spanish"),
3124
		"es_AR" => gettext("Spanish (Argentina)"),
3125
	);
3126

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

    
3131
	//asort($locales);
3132

    
3133
	return $locales;
3134
}
3135

    
3136
function return_hex_ipv4($ipv4) {
3137
	if (!is_ipaddrv4($ipv4)) {
3138
		return(false);
3139
	}
3140

    
3141
	/* we need the hex form of the interface IPv4 address */
3142
	$ip4arr = explode(".", $ipv4);
3143
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
3144
}
3145

    
3146
function convert_ipv6_to_128bit($ipv6) {
3147
	if (!is_ipaddrv6($ipv6)) {
3148
		return(false);
3149
	}
3150

    
3151
	$ip6arr = array();
3152
	$ip6prefix = Net_IPv6::uncompress($ipv6);
3153
	$ip6arr = explode(":", $ip6prefix);
3154
	/* binary presentation of the prefix for all 128 bits. */
3155
	$ip6prefixbin = "";
3156
	foreach ($ip6arr as $element) {
3157
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3158
	}
3159
	return($ip6prefixbin);
3160
}
3161

    
3162
function convert_128bit_to_ipv6($ip6bin) {
3163
	if (strlen($ip6bin) <> 128) {
3164
		return(false);
3165
	}
3166

    
3167
	$ip6arr = array();
3168
	$ip6binarr = array();
3169
	$ip6binarr = str_split($ip6bin, 16);
3170
	foreach ($ip6binarr as $binpart) {
3171
		$ip6arr[] = dechex(bindec($binpart));
3172
	}
3173
	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
3174

    
3175
	return($ip6addr);
3176
}
3177

    
3178

    
3179
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3180
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3181
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3182
/* 6to4 is 16 bits, e.g. 65535 */
3183
function calculate_ipv6_delegation_length($if) {
3184
	global $config;
3185

    
3186
	if (!is_array($config['interfaces'][$if])) {
3187
		return false;
3188
	}
3189

    
3190
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3191
		case "6to4":
3192
			$pdlen = 16;
3193
			break;
3194
		case "6rd":
3195
			$rd6cfg = $config['interfaces'][$if];
3196
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3197
			$pdlen = (64 - ((int) $rd6plen[1] + (32 - (int) $rd6cfg['prefix-6rd-v4plen'])));
3198
			break;
3199
		case "dhcp6":
3200
			$dhcp6cfg = $config['interfaces'][$if];
3201
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3202
			break;
3203
		default:
3204
			$pdlen = 0;
3205
			break;
3206
	}
3207
	return($pdlen);
3208
}
3209

    
3210
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3211
	$prefix = Net_IPv6::uncompress($prefix, true);
3212
	$suffix = Net_IPv6::uncompress($suffix, true);
3213

    
3214
	/*
3215
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3216
	 *                ^^^^ ^
3217
	 *                |||| \-> 64
3218
	 *                |||\---> 63, 62, 61, 60
3219
	 *                ||\----> 56
3220
	 *                |\-----> 52
3221
	 *                \------> 48
3222
	 */
3223

    
3224
	switch ($len) {
3225
	case 48:
3226
		$prefix_len = 15;
3227
		break;
3228
	case 52:
3229
		$prefix_len = 16;
3230
		break;
3231
	case 56:
3232
		$prefix_len = 17;
3233
		break;
3234
	case 59:
3235
	case 60:
3236
		$prefix_len = 18;
3237
		break;
3238
	/*
3239
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
3240
	 * we let user chose this bit it can end up out of PD network
3241
	 *
3242
	 * Leave this with 20 for now until we find a way to let user
3243
	 * chose it. The side-effect is users with PD with one of these
3244
	 * lengths will not be able to setup DHCP server range for full
3245
	 * PD size, only for last /64 network
3246
	 */
3247
	case 63:
3248
	case 62:
3249
	case 61:
3250
	default:
3251
		$prefix_len = 20;
3252
		break;
3253
	}
3254

    
3255
	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
3256
	    substr($suffix, $prefix_len));
3257
}
3258

    
3259
function dhcpv6_pd_str_help($pdlen) {
3260
	$result = '';
3261

    
3262
	switch ($pdlen) {
3263
	case 48:
3264
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
3265
		break;
3266
	case 52:
3267
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
3268
		break;
3269
	case 56:
3270
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
3271
		break;
3272
	case 59:
3273
	case 60:
3274
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
3275
		break;
3276
	/*
3277
	 * XXX 63, 62 and 61 should use same mask as 60 but if
3278
	 * we let the user choose this bit it can end up out of PD network
3279
	 *
3280
	 * Leave this with the same as 64 for now until we find a way to
3281
	 * let the user choose it. The side-effect is users with PD with one
3282
	 * of these lengths will not be able to setup DHCP server ranges
3283
	 * for full PD size, only for last /64 network
3284
	 */
3285
	case 61:
3286
	case 62:
3287
	case 63:
3288
	case 64:
3289
	default:
3290
		$result = '::xxxx:xxxx:xxxx:xxxx';
3291
		break;
3292
	}
3293

    
3294
	return $result;
3295
}
3296

    
3297
function huawei_rssi_to_string($rssi) {
3298
	$dbm = array();
3299
	$i = 0;
3300
	$dbstart = -113;
3301
	while ($i < 32) {
3302
		$dbm[$i] = $dbstart + ($i * 2);
3303
		$i++;
3304
	}
3305
	$percent = round(($rssi / 31) * 100);
3306
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3307
	return $string;
3308
}
3309

    
3310
function huawei_mode_to_string($mode, $submode) {
3311
	$modes[0] = gettext("None");
3312
	$modes[1] = "AMPS";
3313
	$modes[2] = "CDMA";
3314
	$modes[3] = "GSM/GPRS";
3315
	$modes[4] = "HDR";
3316
	$modes[5] = "WCDMA";
3317
	$modes[6] = "GPS";
3318

    
3319
	$submodes[0] = gettext("No Service");
3320
	$submodes[1] = "GSM";
3321
	$submodes[2] = "GPRS";
3322
	$submodes[3] = "EDGE";
3323
	$submodes[4] = "WCDMA";
3324
	$submodes[5] = "HSDPA";
3325
	$submodes[6] = "HSUPA";
3326
	$submodes[7] = "HSDPA+HSUPA";
3327
	$submodes[8] = "TD-SCDMA";
3328
	$submodes[9] = "HSPA+";
3329
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3330
	return $string;
3331
}
3332

    
3333
function huawei_service_to_string($state) {
3334
	$modes[0] = gettext("No Service");
3335
	$modes[1] = gettext("Restricted Service");
3336
	$modes[2] = gettext("Valid Service");
3337
	$modes[3] = gettext("Restricted Regional Service");
3338
	$modes[4] = gettext("Powersaving Service");
3339
	$modes[255] = gettext("Unknown Service");
3340
	$string = $modes[$state];
3341
	return $string;
3342
}
3343

    
3344
function huawei_simstate_to_string($state) {
3345
	$modes[0] = gettext("Invalid SIM/locked State");
3346
	$modes[1] = gettext("Valid SIM State");
3347
	$modes[2] = gettext("Invalid SIM CS State");
3348
	$modes[3] = gettext("Invalid SIM PS State");
3349
	$modes[4] = gettext("Invalid SIM CS/PS State");
3350
	$modes[255] = gettext("Missing SIM State");
3351
	$string = $modes[$state];
3352
	return $string;
3353
}
3354

    
3355
function zte_rssi_to_string($rssi) {
3356
	return huawei_rssi_to_string($rssi);
3357
}
3358

    
3359
function zte_mode_to_string($mode, $submode) {
3360
	$modes[0] = gettext("No Service");
3361
	$modes[1] = gettext("Limited Service");
3362
	$modes[2] = "GPRS";
3363
	$modes[3] = "GSM";
3364
	$modes[4] = "UMTS";
3365
	$modes[5] = "EDGE";
3366
	$modes[6] = "HSDPA";
3367

    
3368
	$submodes[0] = "CS_ONLY";
3369
	$submodes[1] = "PS_ONLY";
3370
	$submodes[2] = "CS_PS";
3371
	$submodes[3] = "CAMPED";
3372
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3373
	return $string;
3374
}
3375

    
3376
function zte_service_to_string($service) {
3377
	$modes[0] = gettext("Initializing Service");
3378
	$modes[1] = gettext("Network Lock error Service");
3379
	$modes[2] = gettext("Network Locked Service");
3380
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3381
	$string = $modes[$service];
3382
	return $string;
3383
}
3384

    
3385
function zte_simstate_to_string($state) {
3386
	$modes[0] = gettext("No action State");
3387
	$modes[1] = gettext("Network lock State");
3388
	$modes[2] = gettext("(U)SIM card lock State");
3389
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3390
	$string = $modes[$state];
3391
	return $string;
3392
}
3393

    
3394
function get_configured_pppoe_server_interfaces() {
3395
	global $config;
3396
	$iflist = array();
3397
	if (is_array($config['pppoes']['pppoe'])) {
3398
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3399
			if ($pppoe['mode'] == "server") {
3400
				$int = "poes". $pppoe['pppoeid'];
3401
				$iflist[$int] = strtoupper($int);
3402
			}
3403
		}
3404
	}
3405
	return $iflist;
3406
}
3407

    
3408
function get_pppoes_child_interfaces($ifpattern) {
3409
	$if_arr = array();
3410
	if ($ifpattern == "") {
3411
		return;
3412
	}
3413

    
3414
	exec("/sbin/ifconfig", $out, $ret);
3415
	foreach ($out as $line) {
3416
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3417
			$if_arr[] = $match[1];
3418
		}
3419
	}
3420
	return $if_arr;
3421

    
3422
}
3423

    
3424
/****f* pfsense-utils/pkg_call_plugins
3425
 * NAME
3426
 *   pkg_call_plugins
3427
 * INPUTS
3428
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3429
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3430
 * RESULT
3431
 *   returns associative array results from the plugin calls for each package
3432
 * NOTES
3433
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3434
 ******/
3435
function pkg_call_plugins($plugin_type, $plugin_params) {
3436
	global $g, $config;
3437
	$results = array();
3438
	if (!is_array($config['installedpackages']['package'])) {
3439
		return $results;
3440
	}
3441
	foreach ($config['installedpackages']['package'] as $package) {
3442
		if (is_array($package['plugins']['item'])) {
3443
			foreach ($package['plugins']['item'] as $plugin) {
3444
				if ($plugin['type'] == $plugin_type) {
3445
					if (file_exists($package['include_file'])) {
3446
						require_once($package['include_file']);
3447
					} else {
3448
						continue;
3449
					}
3450
					$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3451
					$plugin_function = $pkgname . '_'. $plugin_type;
3452
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3453
				}
3454
			}
3455
		}
3456
	}
3457
	return $results;
3458
}
3459

    
3460
// Convert IPv6 addresses to lower case
3461
function addrtolower($ip) {
3462
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3463
		return(strtolower($ip));
3464
	} else {
3465
		return($ip);
3466
	}
3467
}
3468

    
3469
function compare_by_name($a, $b) {
3470
	return strcasecmp($a['name'], $b['name']);
3471
}
3472

    
3473
/****f* pfsense-utils/getarraybyref
3474
 * NAME
3475
 *   getarraybyref
3476
 * INPUTS
3477
 *   $array the array of which a items array needs to be found.
3478
 *   $args.. the sub-items to be retrieved/created
3479
 * RESULT
3480
 *   returns the array that was retrieved from configuration, its created if it does not exist
3481
 * NOTES
3482
 *   Used by haproxy / acme / others.?. .
3483
 *   can be used like this:  $a_certificates = getarraybyref($config, 'installedpackages', 'acme', 'certificates', 'item');
3484
 ******/
3485
function &getarraybyref(&$array) {
3486
	if (!isset($array)) {
3487
		return false;
3488
	}
3489
	if (!is_array($array)) {
3490
		$array = array();
3491
	}
3492
	$item = &$array;
3493
	$arg = func_get_args();
3494
	for($i = 1; $i < count($arg); $i++) {
3495
		$itemindex = $arg[$i];
3496
		if (!is_array($item[$itemindex])) {
3497
			$item[$itemindex] = array();
3498
		}
3499
		$item = &$item[$itemindex];
3500
	}
3501
	return $item;
3502
}
3503

    
3504
/****f* pfsense-utils/send_download_data
3505
 * NAME
3506
 *   send_download_data - Send content to a user's browser as a file to download
3507
 * INPUTS
3508
 *   $type        : The type of download, either 'data' to send the contents of
3509
 *                    a variable or 'file' to send the contents of a file on the
3510
 *                    filesystem.
3511
 *   $content     : For 'data' type, the content to send the user. For 'file'
3512
 *                    type, the full path to the file to send.
3513
 *   $userfilename: The filename presented to the user when downloading. For
3514
 *                    'file' type, this may be omitted and the basename of
3515
 *                    $content will be used instead.
3516
 *   $contenttype : MIME content type of the data. Default "application/octet-stream"
3517
 * RESULT
3518
 *   Sends the data to the browser as a file to download.
3519
 ******/
3520

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

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

    
3528
	/* Cannot determine the filename, so bail. */
3529
	if (empty($name)) {
3530
		exit;
3531
	}
3532

    
3533
	/* Send basic download headers */
3534
	header("Content-Type: {$contenttype}");
3535
	header("Content-Length: {$size}");
3536
	header("Content-Disposition: attachment; filename=" . urlencode($name));
3537

    
3538
	/* Send cache headers */
3539
	if (isset($_SERVER['HTTPS'])) {
3540
		header('Pragma: ');
3541
		header('Cache-Control: ');
3542
	} else {
3543
		header("Pragma: private");
3544
		header("Cache-Control: private, must-revalidate");
3545
	}
3546

    
3547
	/* Ensure output buffering is off so PHP does not consume
3548
	 * memory in readfile(). https://redmine.pfsense.org/issues/9239 */
3549
	while (ob_get_level()) {
3550
		@ob_end_clean();
3551
	}
3552

    
3553
	/* Send the data to the user */
3554
	if ($type == 'file') {
3555
		readfile($content);
3556
	} else {
3557
		echo $content;
3558
	}
3559

    
3560
	/* Flush any remaining output buffer */
3561
	@ob_end_flush();
3562
	exit;
3563
}
3564

    
3565
?>
(38-38/60)