Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

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

    
196
		$css = array_merge($pfscss, $betacss, $usrcss);
197

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

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

    
217
	$csslist = get_css_files();
218

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

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

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

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

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

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

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

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

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

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

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

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

    
346
	$group = new Form_Group('Associated Panels Show/Hide');
347

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

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

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

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

    
376
	$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.');
377

    
378
	$section->add($group);
379
}
380

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
531
		$form->add($section);
532
	}
533
}
534

    
535
function hardware_offloading_applyflags($iface) {
536
	global $config;
537

    
538
	$flags_on = 0;
539
	$flags_off = 0;
540
	$options = pfSense_get_interface_addresses($iface);
541

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

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

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

    
582
	pfSense_interface_capabilities($iface, -$flags_off);
583
	pfSense_interface_capabilities($iface, $flags_on);
584
}
585

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
770
	return "";
771
}
772

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

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

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

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

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

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

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

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

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

    
860
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
861

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

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

    
883
	return false;
884
}
885

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1071
	/* parse config.xml again */
1072
	$config = parse_config(true);
1073

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

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

    
1084
	/* set up interfaces */
1085
	interfaces_configure();
1086
}
1087

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

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

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

    
1123
	/* parse config.xml again */
1124
	$config = parse_config(true);
1125

    
1126
	/* set up our timezone */
1127
	system_timezone_configure();
1128

    
1129
	/* set up our hostname */
1130
	system_hostname_configure();
1131

    
1132
	/* make hosts file */
1133
	system_hosts_generate();
1134

    
1135
	/* generate resolv.conf */
1136
	system_resolvconf_generate();
1137

    
1138
	/* enable routing */
1139
	system_routing_enable();
1140

    
1141
	/* set up interfaces */
1142
	interfaces_configure();
1143

    
1144
	/* start dyndns service */
1145
	services_dyndns_configure();
1146

    
1147
	/* configure cron service */
1148
	configure_cron();
1149

    
1150
	/* start the NTP client */
1151
	system_ntp_configure();
1152

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

    
1157
	/* restart sshd */
1158
	send_event("service restart sshd");
1159

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

    
1164
function load_loader_conf($loader_conf = NULL, $local = false) {
1165

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

    
1175
	$input_split = explode("\n", $input);
1176

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

    
1211
	return ($data);
1212
}
1213

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

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

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

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

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

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

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

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

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

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

    
1314
	safe_write_file($loader_conf_file, $data);
1315

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

    
1325
}
1326

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

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

    
1334
	$ttys = file_get_contents($ttys_file);
1335
	$ttys_split = explode("\n", $ttys);
1336

    
1337
	$data = array();
1338

    
1339
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1340

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

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

    
1355
	$found = array();
1356

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

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

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

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

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

    
1403
	safe_write_file($ttys_file, $data);
1404

    
1405
	unset($ttys, $ttys_file, $ttys_split, $data);
1406

    
1407
	if ($when != "upgrade") {
1408
		reload_ttys();
1409
	}
1410

    
1411
	return;
1412
}
1413

    
1414
function is_serial_enabled() {
1415
	global $g, $config;
1416

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

    
1422
	return true;
1423
}
1424

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

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

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

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

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

    
1454
	return false;
1455
}
1456

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

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

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

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

    
1479
	return false;
1480
}
1481

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

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

    
1490
	$dhcpdv6cfg = $config['dhcpdv6'];
1491
	$Iflist = get_configured_interface_list();
1492

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

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

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

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

    
1512
		return true;
1513
	}
1514

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

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

    
1529
		$ifcfgsnv6 = get_interface_subnetv6($if);
1530
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1531

    
1532
		if (!is_ipaddrv6($subnetv6)) {
1533
			continue;
1534
		}
1535

    
1536
		return true;
1537
	}
1538

    
1539
	return false;
1540
}
1541

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

    
1546
	$pppoeenable = false;
1547

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

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

    
1558
	return $pppoeenable;
1559
}
1560

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

    
1575
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1576

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1846
	return $ifinfo;
1847
}
1848

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

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

    
1864
	$uptime = time() - $boottime;
1865
	return $uptime;
1866
}
1867

    
1868
function add_hostname_to_watch($hostname) {
1869
	if (!is_dir("/var/db/dnscache")) {
1870
		mkdir("/var/db/dnscache");
1871
	}
1872
	$result = array();
1873
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1874
		$domrecords = array();
1875
		$domips = array();
1876
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1877
		if ($rethost == 0) {
1878
			foreach ($domrecords as $domr) {
1879
				$doml = explode(" ", $domr);
1880
				$domip = $doml[3];
1881
				/* fill array with domain ip addresses */
1882
				if (is_ipaddr($domip)) {
1883
					$domips[] = $domip;
1884
				}
1885
			}
1886
		}
1887
		sort($domips);
1888
		$contents = "";
1889
		if (!empty($domips)) {
1890
			foreach ($domips as $ip) {
1891
				$contents .= "$ip\n";
1892
			}
1893
		}
1894
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1895
		/* Remove empty elements */
1896
		$result = array_filter(explode("\n", $contents), 'strlen');
1897
	}
1898
	return $result;
1899
}
1900

    
1901
function is_fqdn($fqdn) {
1902
	$hostname = false;
1903
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1904
		$hostname = true;
1905
	}
1906
	if (preg_match("/\.\./", $fqdn)) {
1907
		$hostname = false;
1908
	}
1909
	if (preg_match("/^\./i", $fqdn)) {
1910
		$hostname = false;
1911
	}
1912
	if (preg_match("/\//i", $fqdn)) {
1913
		$hostname = false;
1914
	}
1915
	return($hostname);
1916
}
1917

    
1918
function pfsense_default_state_size() {
1919
	/* get system memory amount */
1920
	$memory = get_memory();
1921
	$physmem = $memory[0];
1922
	/* Be cautious and only allocate 10% of system memory to the state table */
1923
	$max_states = (int) ($physmem/10)*1000;
1924
	return $max_states;
1925
}
1926

    
1927
function pfsense_default_tables_size() {
1928
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1929
	return $current;
1930
}
1931

    
1932
function pfsense_default_table_entries_size() {
1933
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1934
	return (trim($current));
1935
}
1936

    
1937
/* Compare the current hostname DNS to the DNS cache we made
1938
 * if it has changed we return the old records
1939
 * if no change we return false */
1940
function compare_hostname_to_dnscache($hostname) {
1941
	if (!is_dir("/var/db/dnscache")) {
1942
		mkdir("/var/db/dnscache");
1943
	}
1944
	$hostname = trim($hostname);
1945
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1946
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1947
	} else {
1948
		$oldcontents = "";
1949
	}
1950
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1951
		$domrecords = array();
1952
		$domips = array();
1953
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1954
		if ($rethost == 0) {
1955
			foreach ($domrecords as $domr) {
1956
				$doml = explode(" ", $domr);
1957
				$domip = $doml[3];
1958
				/* fill array with domain ip addresses */
1959
				if (is_ipaddr($domip)) {
1960
					$domips[] = $domip;
1961
				}
1962
			}
1963
		}
1964
		sort($domips);
1965
		$contents = "";
1966
		if (!empty($domips)) {
1967
			foreach ($domips as $ip) {
1968
				$contents .= "$ip\n";
1969
			}
1970
		}
1971
	}
1972

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

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

    
1990
	$enabled_modules = explode('_', $config['system']['crypto_hardware']);
1991

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

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

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

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

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

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

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

    
2042
	return false;
2043
}
2044

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

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

    
2053
	$fp = fopen($destination, "wb");
2054

    
2055
	if (!$fp) {
2056
		return false;
2057
	}
2058

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

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

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

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

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

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

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

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

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

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

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

    
2244
	if ($pkg_interface == "console") {
2245
		print ("{$status}");
2246
	}
2247

    
2248
	/* ensure that contents are written out */
2249
	ob_flush();
2250
}
2251

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

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

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

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

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

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

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

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

    
2350
	if ($debug) {
2351
		fclose($fd);
2352
	}
2353

    
2354
}
2355

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

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

    
2371
	if (filesize($filename) == 0) {
2372
		log_error(sprintf(gettext("Could not process empty file from alias: %s"), $filename));
2373
		return null;
2374
	}
2375
	$fd = @fopen($filename, 'r');
2376
	if (!$fd) {
2377
		log_error(sprintf(gettext("Could not process aliases from alias: %s"), $filename));
2378
		return null;
2379
	}
2380
	$items = array();
2381
	$comments = array();
2382
	/* NOTE: fgetss() is not a typo RTFM before being smart */
2383
	while (($fc = fgetss($fd)) !== FALSE) {
2384
		$tmp = trim($fc, " \t\n\r");
2385
		if (empty($tmp)) {
2386
			continue;
2387
		}
2388
		if (($kflc) && (strpos($tmp, '#') === 0)) {	// Keep Full Line Comments (lines beginning with #).
2389
			$comments[] = $tmp;
2390
		} else {
2391
			$tmp_str = strstr($tmp, '#', true);
2392
			if (!empty($tmp_str)) {
2393
				$tmp = $tmp_str;
2394
			}
2395
			$tmp_str = strstr($tmp, ' ', true);
2396
			if (!empty($tmp_str)) {
2397
				$tmp = $tmp_str;
2398
			}
2399
			$valid = (($type == "url" || $type == "urltable") && (is_ipaddr($tmp) || is_subnet($tmp))) ||
2400
				(($type == "url_ports" || $type == "urltable_ports") && is_port_or_range($tmp));
2401
			if ($valid) {
2402
				$items[] = $tmp;
2403
				if (count($items) == $max_items) {
2404
					break;
2405
				}
2406
			}
2407
		}
2408
	}
2409
	fclose($fd);
2410
	return array_merge($comments, $items);
2411
}
2412

    
2413
function update_alias_url_data() {
2414
	global $config, $g;
2415

    
2416
	$updated = false;
2417

    
2418
	/* item is a url type */
2419
	$lockkey = lock('aliasurl');
2420
	if (is_array($config['aliases']['alias'])) {
2421
		foreach ($config['aliases']['alias'] as $x => $alias) {
2422
			if (empty($alias['aliasurl'])) {
2423
				continue;
2424
			}
2425

    
2426
			$address = null;
2427
			foreach ($alias['aliasurl'] as $alias_url) {
2428
				/* fetch down and add in */
2429
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2430
				unlink($temp_filename);
2431
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2432
				mkdir($temp_filename);
2433
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2434
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2435
					continue;
2436
				}
2437

    
2438
				/* if the item is tar gzipped then extract */
2439
				if (stripos($alias_url, '.tgz')) {
2440
					if (!process_alias_tgz($temp_filename)) {
2441
						continue;
2442
					}
2443
				}
2444
				if (file_exists("{$temp_filename}/aliases")) {
2445
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2446
					mwexec("/bin/rm -rf {$temp_filename}");
2447
				}
2448
			}
2449
			if ($address != null) {
2450
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2451
				$updated = true;
2452
			}
2453
		}
2454
	}
2455
	unlock($lockkey);
2456

    
2457
	/* Report status to callers as well */
2458
	return $updated;
2459
}
2460

    
2461
function process_alias_tgz($temp_filename) {
2462
	if (!file_exists('/usr/bin/tar')) {
2463
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2464
		return false;
2465
	}
2466
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2467
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2468
	unlink("{$temp_filename}/aliases.tgz");
2469
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2470
	/* foreach through all extracted files and build up aliases file */
2471
	$fd = @fopen("{$temp_filename}/aliases", "w");
2472
	if (!$fd) {
2473
		log_error(sprintf(gettext("Could not open %s/aliases for writing!"), $temp_filename));
2474
		return false;
2475
	}
2476
	foreach ($files_to_process as $f2p) {
2477
		$tmpfd = @fopen($f2p, 'r');
2478
		if (!$tmpfd) {
2479
			log_error(sprintf(gettext('The following file could not be read %1$s from %2$s'), $f2p, $temp_filename));
2480
			continue;
2481
		}
2482
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2483
			fwrite($fd, $tmpbuf);
2484
		}
2485
		fclose($tmpfd);
2486
		unlink($f2p);
2487
	}
2488
	fclose($fd);
2489
	unset($tmpbuf);
2490

    
2491
	return true;
2492
}
2493

    
2494
function version_compare_dates($a, $b) {
2495
	$a_time = strtotime($a);
2496
	$b_time = strtotime($b);
2497

    
2498
	if ((!$a_time) || (!$b_time)) {
2499
		return FALSE;
2500
	} else {
2501
		if ($a_time < $b_time) {
2502
			return -1;
2503
		} elseif ($a_time == $b_time) {
2504
			return 0;
2505
		} else {
2506
			return 1;
2507
		}
2508
	}
2509
}
2510
function version_get_string_value($a) {
2511
	$strs = array(
2512
		0 => "ALPHA-ALPHA",
2513
		2 => "ALPHA",
2514
		3 => "BETA",
2515
		4 => "B",
2516
		5 => "C",
2517
		6 => "D",
2518
		7 => "RC",
2519
		8 => "RELEASE",
2520
		9 => "*"			// Matches all release levels
2521
	);
2522
	$major = 0;
2523
	$minor = 0;
2524
	foreach ($strs as $num => $str) {
2525
		if (substr($a, 0, strlen($str)) == $str) {
2526
			$major = $num;
2527
			$n = substr($a, strlen($str));
2528
			if (is_numeric($n)) {
2529
				$minor = $n;
2530
			}
2531
			break;
2532
		}
2533
	}
2534
	return "{$major}.{$minor}";
2535
}
2536
function version_compare_string($a, $b) {
2537
	// Only compare string parts if both versions give a specific release
2538
	// (If either version lacks a string part, assume intended to match all release levels)
2539
	if (isset($a) && isset($b)) {
2540
		return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
2541
	} else {
2542
		return 0;
2543
	}
2544
}
2545
function version_compare_numeric($a, $b) {
2546
	$a_arr = explode('.', rtrim($a, '.'));
2547
	$b_arr = explode('.', rtrim($b, '.'));
2548

    
2549
	foreach ($a_arr as $n => $val) {
2550
		if (array_key_exists($n, $b_arr)) {
2551
			// So far so good, both have values at this minor version level. Compare.
2552
			if ($val > $b_arr[$n]) {
2553
				return 1;
2554
			} elseif ($val < $b_arr[$n]) {
2555
				return -1;
2556
			}
2557
		} else {
2558
			// a is greater, since b doesn't have any minor version here.
2559
			return 1;
2560
		}
2561
	}
2562
	if (count($b_arr) > count($a_arr)) {
2563
		// b is longer than a, so it must be greater.
2564
		return -1;
2565
	} else {
2566
		// Both a and b are of equal length and value.
2567
		return 0;
2568
	}
2569
}
2570
function pfs_version_compare($cur_time, $cur_text, $remote) {
2571
	// First try date compare
2572
	$v = version_compare_dates($cur_time, $remote);
2573
	if ($v === FALSE) {
2574
		// If that fails, try to compare by string
2575
		// Before anything else, simply test if the strings are equal
2576
		if (($cur_text == $remote) || ($cur_time == $remote)) {
2577
			return 0;
2578
		}
2579
		list($cur_num, $cur_str) = explode('-', $cur_text);
2580
		list($rem_num, $rem_str) = explode('-', $remote);
2581

    
2582
		// First try to compare the numeric parts of the version string.
2583
		$v = version_compare_numeric($cur_num, $rem_num);
2584

    
2585
		// If the numeric parts are the same, compare the string parts.
2586
		if ($v == 0) {
2587
			return version_compare_string($cur_str, $rem_str);
2588
		}
2589
	}
2590
	return $v;
2591
}
2592
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2593
	global $g, $config;
2594

    
2595
	$urltable_prefix = "/var/db/aliastables/";
2596
	$urltable_filename = $urltable_prefix . $name . ".txt";
2597
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2598

    
2599
	// Make the aliases directory if it doesn't exist
2600
	if (!file_exists($urltable_prefix)) {
2601
		mkdir($urltable_prefix);
2602
	} elseif (!is_dir($urltable_prefix)) {
2603
		unlink($urltable_prefix);
2604
		mkdir($urltable_prefix);
2605
	}
2606

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

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

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

    
2621
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2622
			if ($type == "urltable_ports") {
2623
				$parsed_contents = group_ports($parsed_contents, true);
2624
			}
2625
			if (is_array($parsed_contents)) {
2626
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2627
			} else {
2628
				touch($urltable_filename);
2629
			}
2630

    
2631
			/* Remove existing archive and create an up to date archive if RAM disk is enabled. */
2632
			unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz");
2633
			if (isset($config['system']['use_mfs_tmpvar'])) {
2634
				mwexec("/usr/bin/tar -czf " . escapeshellarg("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz") . " -C / " . escapeshellarg($urltable_filename));
2635
			}
2636

    
2637
			unlink_if_exists($tmp_urltable_filename);
2638
		} else {
2639
			if (!$validateonly) {
2640
				touch($urltable_filename);
2641
			}
2642
			return false;
2643
		}
2644
		return true;
2645
	} else {
2646
		// File exists, and it doesn't need to be updated.
2647
		return -1;
2648
	}
2649
}
2650

    
2651
function get_include_contents($filename) {
2652
	if (is_file($filename)) {
2653
		ob_start();
2654
		include $filename;
2655
		$contents = ob_get_contents();
2656
		ob_end_clean();
2657
		return $contents;
2658
	}
2659
	return false;
2660
}
2661

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

    
2774
function get_country_name($country_code = "ALL") {
2775
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2776
		return "";
2777
	}
2778

    
2779
	$country_names_xml = "/usr/local/share/pfSense/iso_3166-1_list_en.xml";
2780
	$country_names_contents = file_get_contents($country_names_xml);
2781
	$country_names = xml2array($country_names_contents);
2782

    
2783
	if ($country_code == "ALL") {
2784
		$country_list = array();
2785
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2786
			$country_list[] = array(
2787
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2788
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2789
		}
2790
		return $country_list;
2791
	}
2792

    
2793
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2794
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2795
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2796
		}
2797
	}
2798
	return "";
2799
}
2800

    
2801
/* Return the list of country codes to be used on CAs and certs */
2802
function get_cert_country_codes() {
2803
	$countries = get_country_name();
2804

    
2805
	$country_codes = array();
2806
	foreach ($countries as $country) {
2807
		$country_codes[$country['code']] = $country['code'];
2808
	}
2809
	ksort($country_codes);
2810

    
2811
	/* Preserve historical order: None, US, CA, other countries */
2812
	$first_items[''] = gettext("None");
2813
	$first_items['US'] = $country_codes['US'];
2814
	$first_items['CA'] = $country_codes['CA'];
2815
	unset($country_codes['US']);
2816
	unset($country_codes['CA']);
2817

    
2818
	return array_merge($first_items, $country_codes);
2819
}
2820

    
2821
/* sort by interface only, retain the original order of rules that apply to
2822
   the same interface */
2823
function filter_rules_sort() {
2824
	global $config;
2825

    
2826
	init_config_arr(array('filter', 'rule'));
2827
	/* mark each rule with the sequence number (to retain the order while sorting) */
2828
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2829
		if (!is_array($config['filter']['rule'][$i])) {
2830
			$config['filter']['rule'][$i] = array();
2831
		}
2832
		$config['filter']['rule'][$i]['seq'] = $i;
2833
	}
2834

    
2835
	usort($config['filter']['rule'], "filter_rules_compare");
2836

    
2837
	/* strip the sequence numbers again */
2838
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2839
		unset($config['filter']['rule'][$i]['seq']);
2840
	}
2841
}
2842
function filter_rules_compare($a, $b) {
2843
	if (isset($a['floating']) && isset($b['floating'])) {
2844
		return $a['seq'] - $b['seq'];
2845
	} else if (isset($a['floating'])) {
2846
		return -1;
2847
	} else if (isset($b['floating'])) {
2848
		return 1;
2849
	} else if ($a['interface'] == $b['interface']) {
2850
		return $a['seq'] - $b['seq'];
2851
	} else {
2852
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2853
	}
2854
}
2855

    
2856
function generate_ipv6_from_mac($mac) {
2857
	$elements = explode(":", $mac);
2858
	if (count($elements) <> 6) {
2859
		return false;
2860
	}
2861

    
2862
	$i = 0;
2863
	$ipv6 = "fe80::";
2864
	foreach ($elements as $byte) {
2865
		if ($i == 0) {
2866
			$hexadecimal = substr($byte, 1, 2);
2867
			$bitmap = base_convert($hexadecimal, 16, 2);
2868
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2869
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2870
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2871
		}
2872
		$ipv6 .= $byte;
2873
		if ($i == 1) {
2874
			$ipv6 .= ":";
2875
		}
2876
		if ($i == 3) {
2877
			$ipv6 .= ":";
2878
		}
2879
		if ($i == 2) {
2880
			$ipv6 .= "ff:fe";
2881
		}
2882

    
2883
		$i++;
2884
	}
2885
	return $ipv6;
2886
}
2887

    
2888
/****f* pfsense-utils/load_mac_manufacturer_table
2889
 * NAME
2890
 *   load_mac_manufacturer_table
2891
 * INPUTS
2892
 *   none
2893
 * RESULT
2894
 *   returns associative array with MAC-Manufacturer pairs
2895
 ******/
2896
function load_mac_manufacturer_table() {
2897
	/* load MAC-Manufacture data from the file */
2898
	$macs = false;
2899
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2900
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2901
	}
2902
	if ($macs) {
2903
		foreach ($macs as $line) {
2904
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2905
				/* store values like this $mac_man['000C29']='VMware' */
2906
				$mac_man["$matches[1]"] = $matches[2];
2907
			}
2908
		}
2909
		return $mac_man;
2910
	} else {
2911
		return -1;
2912
	}
2913

    
2914
}
2915

    
2916
/****f* pfsense-utils/is_ipaddr_configured
2917
 * NAME
2918
 *   is_ipaddr_configured
2919
 * INPUTS
2920
 *   IP Address to check.
2921
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2922
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2923
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2924
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2925
 *     If check_subnets is true and cidrprefix is specified,
2926
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2927
 * RESULT
2928
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2929
*/
2930
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2931
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2932
		return true;
2933
	}
2934
	return false;
2935
}
2936

    
2937
/****f* pfsense-utils/where_is_ipaddr_configured
2938
 * NAME
2939
 *   where_is_ipaddr_configured
2940
 * INPUTS
2941
 *   IP Address to check.
2942
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2943
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2944
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2945
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2946
 *     If check_subnets is true and cidrprefix is specified,
2947
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2948
 * RESULT
2949
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2950
 *   If there are no matches then an empty array is returned.
2951
*/
2952
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2953
	global $config;
2954

    
2955
	$where_configured = array();
2956

    
2957
	$pos = strpos($ignore_if, '_virtualip');
2958
	if ($pos !== false) {
2959
		$ignore_vip_id = substr($ignore_if, $pos+10);
2960
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2961
	} else {
2962
		$ignore_vip_id = -1;
2963
		$ignore_vip_if = $ignore_if;
2964
	}
2965

    
2966
	$isipv6 = is_ipaddrv6($ipaddr);
2967

    
2968
	if ($isipv6) {
2969
		$ipaddr = text_to_compressed_ip6($ipaddr);
2970
	}
2971

    
2972
	if ($check_subnets) {
2973
		$cidrprefix = intval($cidrprefix);
2974
		if ($isipv6) {
2975
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2976
				$cidrprefix = 128;
2977
			}
2978
		} else {
2979
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2980
				$cidrprefix = 32;
2981
			}
2982
		}
2983
		$iflist = get_configured_interface_list();
2984
		foreach ($iflist as $if => $ifname) {
2985
			if ($ignore_if == $if) {
2986
				continue;
2987
			}
2988

    
2989
			if ($isipv6) {
2990
				$if_ipv6 = get_interface_ipv6($if);
2991
				$if_snbitsv6 = get_interface_subnetv6($if);
2992
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2993
					$where_entry = array();
2994
					$where_entry['if'] = $if;
2995
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2996
					$where_configured[] = $where_entry;
2997
				}
2998
			} else {
2999
				$if_ipv4 = get_interface_ip($if);
3000
				$if_snbitsv4 = get_interface_subnet($if);
3001
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
3002
					$where_entry = array();
3003
					$where_entry['if'] = $if;
3004
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
3005
					$where_configured[] = $where_entry;
3006
				}
3007
			}
3008
		}
3009
	} else {
3010
		if ($isipv6) {
3011
			$interface_list_ips = get_configured_ipv6_addresses();
3012
		} else {
3013
			$interface_list_ips = get_configured_ip_addresses();
3014
		}
3015

    
3016
		foreach ($interface_list_ips as $if => $ilips) {
3017
			if ($ignore_if == $if) {
3018
				continue;
3019
			}
3020
			if (strcasecmp($ipaddr, $ilips) == 0) {
3021
				$where_entry = array();
3022
				$where_entry['if'] = $if;
3023
				$where_entry['ip_or_subnet'] = $ilips;
3024
				$where_configured[] = $where_entry;
3025
			}
3026
		}
3027
	}
3028

    
3029
	if ($check_localip) {
3030
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, text_to_compressed_ip6($config['l2tp']['localip'])) == 0)) {
3031
			$where_entry = array();
3032
			$where_entry['if'] = 'l2tp';
3033
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
3034
			$where_configured[] = $where_entry;
3035
		}
3036
	}
3037

    
3038
	return $where_configured;
3039
}
3040

    
3041
/****f* pfsense-utils/pfSense_handle_custom_code
3042
 * NAME
3043
 *   pfSense_handle_custom_code
3044
 * INPUTS
3045
 *   directory name to process
3046
 * RESULT
3047
 *   globs the directory and includes the files
3048
 */
3049
function pfSense_handle_custom_code($src_dir) {
3050
	// Allow extending of the nat edit page and include custom input validation
3051
	if (is_dir("$src_dir")) {
3052
		$cf = glob($src_dir . "/*.inc");
3053
		foreach ($cf as $nf) {
3054
			if ($nf == "." || $nf == "..") {
3055
				continue;
3056
			}
3057
			// Include the extra handler
3058
			include_once("$nf");
3059
		}
3060
	}
3061
}
3062

    
3063
function set_language() {
3064
	global $config, $g;
3065

    
3066
	if (!empty($config['system']['language'])) {
3067
		$lang = $config['system']['language'];
3068
	} elseif (!empty($g['language'])) {
3069
		$lang = $g['language'];
3070
	}
3071
	$lang .= ".UTF-8";
3072

    
3073
	putenv("LANG={$lang}");
3074
	setlocale(LC_ALL, $lang);
3075
	textdomain("pfSense");
3076
	bindtextdomain("pfSense", "/usr/local/share/locale");
3077
	bind_textdomain_codeset("pfSense", $lang);
3078
}
3079

    
3080
function get_locale_list() {
3081
	$locales = array(
3082
		"bs" => gettext("Bosnian"),
3083
		"zh_CN" => gettext("Chinese"),
3084
		"zh_Hans_CN" => gettext("Chinese (Simplified, China)"),
3085
		"zh_HK" => gettext("Chinese (Hong Kong)"),
3086
		"zh_TW" => gettext("Chinese (Taiwan)"),
3087
		"nl" => gettext("Dutch"),
3088
		"en_US" => gettext("English"),
3089
		"fr" => gettext("French"),
3090
		"de_DE" => gettext("German (Germany)"),
3091
		"ko" => gettext("Korean"),
3092
		"nb" => gettext("Norwegian Bokmål"),
3093
		"pl" => gettext("Polish"),
3094
		"pt_PT" => gettext("Portuguese"),
3095
		"pt_BR" => gettext("Portuguese (Brazil)"),
3096
		"ru" => gettext("Russian"),
3097
		"es" => gettext("Spanish"),
3098
		"es_AR" => gettext("Spanish (Argentina)"),
3099
	);
3100

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

    
3105
	//asort($locales);
3106

    
3107
	return $locales;
3108
}
3109

    
3110
function return_hex_ipv4($ipv4) {
3111
	if (!is_ipaddrv4($ipv4)) {
3112
		return(false);
3113
	}
3114

    
3115
	/* we need the hex form of the interface IPv4 address */
3116
	$ip4arr = explode(".", $ipv4);
3117
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
3118
}
3119

    
3120
function convert_ipv6_to_128bit($ipv6) {
3121
	if (!is_ipaddrv6($ipv6)) {
3122
		return(false);
3123
	}
3124

    
3125
	$ip6arr = array();
3126
	$ip6prefix = Net_IPv6::uncompress($ipv6);
3127
	$ip6arr = explode(":", $ip6prefix);
3128
	/* binary presentation of the prefix for all 128 bits. */
3129
	$ip6prefixbin = "";
3130
	foreach ($ip6arr as $element) {
3131
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3132
	}
3133
	return($ip6prefixbin);
3134
}
3135

    
3136
function convert_128bit_to_ipv6($ip6bin) {
3137
	if (strlen($ip6bin) <> 128) {
3138
		return(false);
3139
	}
3140

    
3141
	$ip6arr = array();
3142
	$ip6binarr = array();
3143
	$ip6binarr = str_split($ip6bin, 16);
3144
	foreach ($ip6binarr as $binpart) {
3145
		$ip6arr[] = dechex(bindec($binpart));
3146
	}
3147
	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
3148

    
3149
	return($ip6addr);
3150
}
3151

    
3152

    
3153
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3154
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3155
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3156
/* 6to4 is 16 bits, e.g. 65535 */
3157
function calculate_ipv6_delegation_length($if) {
3158
	global $config;
3159

    
3160
	if (!is_array($config['interfaces'][$if])) {
3161
		return false;
3162
	}
3163

    
3164
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3165
		case "6to4":
3166
			$pdlen = 16;
3167
			break;
3168
		case "6rd":
3169
			$rd6cfg = $config['interfaces'][$if];
3170
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3171
			$pdlen = (64 - ((int) $rd6plen[1] + (32 - (int) $rd6cfg['prefix-6rd-v4plen'])));
3172
			break;
3173
		case "dhcp6":
3174
			$dhcp6cfg = $config['interfaces'][$if];
3175
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3176
			break;
3177
		default:
3178
			$pdlen = 0;
3179
			break;
3180
	}
3181
	return($pdlen);
3182
}
3183

    
3184
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3185
	$prefix = Net_IPv6::uncompress($prefix, true);
3186
	$suffix = Net_IPv6::uncompress($suffix, true);
3187

    
3188
	/*
3189
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3190
	 *                ^^^^ ^
3191
	 *                |||| \-> 64
3192
	 *                |||\---> 63, 62, 61, 60
3193
	 *                ||\----> 56
3194
	 *                |\-----> 52
3195
	 *                \------> 48
3196
	 */
3197

    
3198
	switch ($len) {
3199
	case 48:
3200
		$prefix_len = 15;
3201
		break;
3202
	case 52:
3203
		$prefix_len = 16;
3204
		break;
3205
	case 56:
3206
		$prefix_len = 17;
3207
		break;
3208
	case 59:
3209
	case 60:
3210
		$prefix_len = 18;
3211
		break;
3212
	/*
3213
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
3214
	 * we let user chose this bit it can end up out of PD network
3215
	 *
3216
	 * Leave this with 20 for now until we find a way to let user
3217
	 * chose it. The side-effect is users with PD with one of these
3218
	 * lengths will not be able to setup DHCP server range for full
3219
	 * PD size, only for last /64 network
3220
	 */
3221
	case 63:
3222
	case 62:
3223
	case 61:
3224
	default:
3225
		$prefix_len = 20;
3226
		break;
3227
	}
3228

    
3229
	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
3230
	    substr($suffix, $prefix_len));
3231
}
3232

    
3233
function dhcpv6_pd_str_help($pdlen) {
3234
	$result = '';
3235

    
3236
	switch ($pdlen) {
3237
	case 48:
3238
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
3239
		break;
3240
	case 52:
3241
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
3242
		break;
3243
	case 56:
3244
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
3245
		break;
3246
	case 59:
3247
	case 60:
3248
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
3249
		break;
3250
	/*
3251
	 * XXX 63, 62 and 61 should use same mask as 60 but if
3252
	 * we let the user choose this bit it can end up out of PD network
3253
	 *
3254
	 * Leave this with the same as 64 for now until we find a way to
3255
	 * let the user choose it. The side-effect is users with PD with one
3256
	 * of these lengths will not be able to setup DHCP server ranges
3257
	 * for full PD size, only for last /64 network
3258
	 */
3259
	case 61:
3260
	case 62:
3261
	case 63:
3262
	case 64:
3263
	default:
3264
		$result = '::xxxx:xxxx:xxxx:xxxx';
3265
		break;
3266
	}
3267

    
3268
	return $result;
3269
}
3270

    
3271
function huawei_rssi_to_string($rssi) {
3272
	$dbm = array();
3273
	$i = 0;
3274
	$dbstart = -113;
3275
	while ($i < 32) {
3276
		$dbm[$i] = $dbstart + ($i * 2);
3277
		$i++;
3278
	}
3279
	$percent = round(($rssi / 31) * 100);
3280
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3281
	return $string;
3282
}
3283

    
3284
function huawei_mode_to_string($mode, $submode) {
3285
	$modes[0] = gettext("None");
3286
	$modes[1] = "AMPS";
3287
	$modes[2] = "CDMA";
3288
	$modes[3] = "GSM/GPRS";
3289
	$modes[4] = "HDR";
3290
	$modes[5] = "WCDMA";
3291
	$modes[6] = "GPS";
3292

    
3293
	$submodes[0] = gettext("No Service");
3294
	$submodes[1] = "GSM";
3295
	$submodes[2] = "GPRS";
3296
	$submodes[3] = "EDGE";
3297
	$submodes[4] = "WCDMA";
3298
	$submodes[5] = "HSDPA";
3299
	$submodes[6] = "HSUPA";
3300
	$submodes[7] = "HSDPA+HSUPA";
3301
	$submodes[8] = "TD-SCDMA";
3302
	$submodes[9] = "HSPA+";
3303
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3304
	return $string;
3305
}
3306

    
3307
function huawei_service_to_string($state) {
3308
	$modes[0] = gettext("No Service");
3309
	$modes[1] = gettext("Restricted Service");
3310
	$modes[2] = gettext("Valid Service");
3311
	$modes[3] = gettext("Restricted Regional Service");
3312
	$modes[4] = gettext("Powersaving Service");
3313
	$modes[255] = gettext("Unknown Service");
3314
	$string = $modes[$state];
3315
	return $string;
3316
}
3317

    
3318
function huawei_simstate_to_string($state) {
3319
	$modes[0] = gettext("Invalid SIM/locked State");
3320
	$modes[1] = gettext("Valid SIM State");
3321
	$modes[2] = gettext("Invalid SIM CS State");
3322
	$modes[3] = gettext("Invalid SIM PS State");
3323
	$modes[4] = gettext("Invalid SIM CS/PS State");
3324
	$modes[255] = gettext("Missing SIM State");
3325
	$string = $modes[$state];
3326
	return $string;
3327
}
3328

    
3329
function zte_rssi_to_string($rssi) {
3330
	return huawei_rssi_to_string($rssi);
3331
}
3332

    
3333
function zte_mode_to_string($mode, $submode) {
3334
	$modes[0] = gettext("No Service");
3335
	$modes[1] = gettext("Limited Service");
3336
	$modes[2] = "GPRS";
3337
	$modes[3] = "GSM";
3338
	$modes[4] = "UMTS";
3339
	$modes[5] = "EDGE";
3340
	$modes[6] = "HSDPA";
3341

    
3342
	$submodes[0] = "CS_ONLY";
3343
	$submodes[1] = "PS_ONLY";
3344
	$submodes[2] = "CS_PS";
3345
	$submodes[3] = "CAMPED";
3346
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3347
	return $string;
3348
}
3349

    
3350
function zte_service_to_string($service) {
3351
	$modes[0] = gettext("Initializing Service");
3352
	$modes[1] = gettext("Network Lock error Service");
3353
	$modes[2] = gettext("Network Locked Service");
3354
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3355
	$string = $modes[$service];
3356
	return $string;
3357
}
3358

    
3359
function zte_simstate_to_string($state) {
3360
	$modes[0] = gettext("No action State");
3361
	$modes[1] = gettext("Network lock State");
3362
	$modes[2] = gettext("(U)SIM card lock State");
3363
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3364
	$string = $modes[$state];
3365
	return $string;
3366
}
3367

    
3368
function get_configured_pppoe_server_interfaces() {
3369
	global $config;
3370
	$iflist = array();
3371
	if (is_array($config['pppoes']['pppoe'])) {
3372
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3373
			if ($pppoe['mode'] == "server") {
3374
				$int = "poes". $pppoe['pppoeid'];
3375
				$iflist[$int] = strtoupper($int);
3376
			}
3377
		}
3378
	}
3379
	return $iflist;
3380
}
3381

    
3382
function get_pppoes_child_interfaces($ifpattern) {
3383
	$if_arr = array();
3384
	if ($ifpattern == "") {
3385
		return;
3386
	}
3387

    
3388
	exec("/sbin/ifconfig", $out, $ret);
3389
	foreach ($out as $line) {
3390
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3391
			$if_arr[] = $match[1];
3392
		}
3393
	}
3394
	return $if_arr;
3395

    
3396
}
3397

    
3398
/****f* pfsense-utils/pkg_call_plugins
3399
 * NAME
3400
 *   pkg_call_plugins
3401
 * INPUTS
3402
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3403
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3404
 * RESULT
3405
 *   returns associative array results from the plugin calls for each package
3406
 * NOTES
3407
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3408
 ******/
3409
function pkg_call_plugins($plugin_type, $plugin_params) {
3410
	global $g, $config;
3411
	$results = array();
3412
	if (!is_array($config['installedpackages']['package'])) {
3413
		return $results;
3414
	}
3415
	foreach ($config['installedpackages']['package'] as $package) {
3416
		if (is_array($package['plugins']['item'])) {
3417
			foreach ($package['plugins']['item'] as $plugin) {
3418
				if ($plugin['type'] == $plugin_type) {
3419
					if (file_exists($package['include_file'])) {
3420
						require_once($package['include_file']);
3421
					} else {
3422
						continue;
3423
					}
3424
					$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3425
					$plugin_function = $pkgname . '_'. $plugin_type;
3426
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3427
				}
3428
			}
3429
		}
3430
	}
3431
	return $results;
3432
}
3433

    
3434
// Convert IPv6 addresses to lower case
3435
function addrtolower($ip) {
3436
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3437
		return(strtolower($ip));
3438
	} else {
3439
		return($ip);
3440
	}
3441
}
3442

    
3443
function compare_by_name($a, $b) {
3444
	return strcasecmp($a['name'], $b['name']);
3445
}
3446

    
3447
/****f* pfsense-utils/getarraybyref
3448
 * NAME
3449
 *   getarraybyref
3450
 * INPUTS
3451
 *   $array the array of which a items array needs to be found. 
3452
 *   $args.. the sub-items to be retrieved/created
3453
 * RESULT
3454
 *   returns the array that was retrieved from configuration, its created if it does not exist
3455
 * NOTES
3456
 *   Used by haproxy / acme / others.?. . 
3457
 *   can be used like this:  $a_certificates = getarraybyref($config, 'installedpackages', 'acme', 'certificates', 'item');
3458
 ******/
3459
function &getarraybyref(&$array) {
3460
	if (!isset($array)) {
3461
		return false;
3462
	}
3463
	if (!is_array($array)) {
3464
		$array = array();
3465
	}
3466
	$item = &$array;
3467
	$arg = func_get_args();
3468
	for($i = 1; $i < count($arg); $i++) {
3469
		$itemindex = $arg[$i];
3470
		if (!is_array($item[$itemindex])) {
3471
			$item[$itemindex] = array();
3472
		}
3473
		$item = &$item[$itemindex];
3474
	}
3475
	return $item;
3476
}
3477

    
3478
?>
(38-38/59)