Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
219
	$csslist = get_css_files();
220

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

    
225
	$section->addInput(new Form_Select(
226
		'webguicss',
227
		'Theme',
228
		$value,
229
		$csslist
230
	))->setHelp('Choose an alternative css file (if installed) to change the appearance of the webConfigurator. css files are located in /usr/local/www/css/%s', '<span id="csstxt"></span>');
231
}
232
function validate_webguicss_field(&$input_errors, $value) {
233
	$csslist = get_css_files();
234
	if (!isset($csslist[$value])) {
235
		$input_errors[] = gettext("The submitted Theme could not be found. Pick a different theme.");
236
	}
237
}
238

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
378
	$group->setHelp('These options allow certain panels to be automatically hidden on page load. A control is provided in the title bar to un-hide the panel.');
379

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
772
	return "";
773
}
774

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

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

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

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

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

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

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

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

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

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

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

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

    
885
	return false;
886
}
887

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1213
	return ($data);
1214
}
1215

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

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

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

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

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

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

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

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

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

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

    
1316
	safe_write_file($loader_conf_file, $data);
1317

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

    
1327
}
1328

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

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

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

    
1339
	$data = array();
1340

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

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

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

    
1357
	$found = array();
1358

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

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

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

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

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

    
1405
	safe_write_file($ttys_file, $data);
1406

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

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

    
1413
	return;
1414
}
1415

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

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

    
1424
	return true;
1425
}
1426

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

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

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

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

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

    
1456
	return false;
1457
}
1458

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

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

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

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

    
1481
	return false;
1482
}
1483

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

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

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

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

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

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

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

    
1514
		return true;
1515
	}
1516

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

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

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

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

    
1538
		return true;
1539
	}
1540

    
1541
	return false;
1542
}
1543

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

    
1548
	$pppoeenable = false;
1549

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

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

    
1560
	return $pppoeenable;
1561
}
1562

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1848
	return $ifinfo;
1849
}
1850

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

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

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

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

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

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

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

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

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

    
1962
	if (trim($oldcontents) != trim($contents)) {
1963
		if ($g['debug']) {
1964
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1965
		}
1966
		return ($oldcontents);
1967
	} else {
1968
		return false;
1969
	}
1970
}
1971

    
1972
/*
1973
 * load_crypto() - Load crypto modules if enabled in config.
1974
 */
1975
function load_crypto() {
1976
	global $config, $g;
1977
	$crypto_modules = array('aesni', 'cryptodev');
1978

    
1979
	$enabled_modules = explode('_', $config['system']['crypto_hardware']);
1980

    
1981
	foreach ($enabled_modules as $enmod) {
1982
		if (empty($enmod) || !in_array($enmod, $crypto_modules)) {
1983
			continue;
1984
		}
1985
		if (!is_module_loaded($enmod)) {
1986
			log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $enmod));
1987
			mwexec("/sbin/kldload " . escapeshellarg($enmod));
1988
		}
1989
	}
1990
}
1991

    
1992
/*
1993
 * load_thermal_hardware() - Load temperature monitor kernel module
1994
 */
1995
function load_thermal_hardware() {
1996
	global $config, $g;
1997
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1998

    
1999
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
2000
		return false;
2001
	}
2002

    
2003
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
2004
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
2005
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
2006
	}
2007
}
2008

    
2009
/****f* pfsense-utils/isvm
2010
 * NAME
2011
 *   isvm
2012
 * INPUTS
2013
 *	none
2014
 * RESULT
2015
 *   returns true if machine is running under a virtual environment
2016
 ******/
2017
function isvm() {
2018
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
2019
	$_gb = exec('/bin/kenv -q smbios.system.product 2>/dev/null', $output, $rc);
2020

    
2021
	if ($rc != 0 || !isset($output[0])) {
2022
		return false;
2023
	}
2024

    
2025
	foreach ($virtualenvs as $virtualenv) {
2026
		if (stripos($output[0], $virtualenv) !== false) {
2027
			return true;
2028
		}
2029
	}
2030

    
2031
	return false;
2032
}
2033

    
2034
function get_freebsd_version() {
2035
	$version = explode(".", php_uname("r"));
2036
	return $version[0];
2037
}
2038

    
2039
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
2040
	global $config, $g;
2041

    
2042
	$fp = fopen($destination, "wb");
2043

    
2044
	if (!$fp) {
2045
		return false;
2046
	}
2047

    
2048
	$ch = curl_init();
2049
	curl_setopt($ch, CURLOPT_URL, $url);
2050
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
2051
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2052
	curl_setopt($ch, CURLOPT_FILE, $fp);
2053
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2054
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2055
	curl_setopt($ch, CURLOPT_HEADER, false);
2056
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2057
	if (!isset($config['system']['do_not_send_uniqueid'])) {
2058
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
2059
	} else {
2060
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2061
	}
2062

    
2063
	if (!empty($config['system']['proxyurl'])) {
2064
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2065
		if (!empty($config['system']['proxyport'])) {
2066
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2067
		}
2068
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2069
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2070
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2071
		}
2072
	}
2073

    
2074
	@curl_exec($ch);
2075
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2076
	fclose($fp);
2077
	curl_close($ch);
2078
	if ($http_code == 200) {
2079
		return true;
2080
	} else {
2081
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2082
		unlink_if_exists($destination);
2083
		return false;
2084
	}
2085
}
2086

    
2087
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
2088
	global $config, $g;
2089
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
2090
	$file_size = 1;
2091
	$downloaded = 1;
2092
	$first_progress_update = TRUE;
2093
	/* open destination file */
2094
	$fout = fopen($destination, "wb");
2095

    
2096
	if (!$fout) {
2097
		return false;
2098
	}
2099
	/*
2100
	 *      Originally by Author: Keyvan Minoukadeh
2101
	 *      Modified by Scott Ullrich to return Content-Length size
2102
	 */
2103
	$ch = curl_init();
2104
	curl_setopt($ch, CURLOPT_URL, $url);
2105
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
2106
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2107
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
2108
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2109
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
2110
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
2111
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2112
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2113
	if (!isset($config['system']['do_not_send_uniqueid'])) {
2114
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
2115
	} else {
2116
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2117
	}
2118

    
2119
	if (!empty($config['system']['proxyurl'])) {
2120
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2121
		if (!empty($config['system']['proxyport'])) {
2122
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2123
		}
2124
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2125
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2126
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2127
		}
2128
	}
2129

    
2130
	@curl_exec($ch);
2131
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2132
	fclose($fout);
2133
	curl_close($ch);
2134
	if ($http_code == 200) {
2135
		return true;
2136
	} else {
2137
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2138
		unlink_if_exists($destination);
2139
		return false;
2140
	}
2141
}
2142

    
2143
function read_header($ch, $string) {
2144
	global $file_size, $fout;
2145
	$length = strlen($string);
2146
	$regs = "";
2147
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
2148
	if ($regs[2] <> "") {
2149
		$file_size = intval($regs[2]);
2150
	}
2151
	ob_flush();
2152
	return $length;
2153
}
2154

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

    
2207
/*
2208
 *   update_output_window: update bottom textarea dynamically.
2209
 */
2210
function update_output_window($text) {
2211
	global $pkg_interface;
2212
	$log = preg_replace("/\n/", "\\n", $text);
2213
	if ($pkg_interface != "console") {
2214
?>
2215
<script type="text/javascript">
2216
//<![CDATA[
2217
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
2218
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
2219
//]]>
2220
</script>
2221
<?php
2222
	}
2223
	/* ensure that contents are written out */
2224
	ob_flush();
2225
}
2226

    
2227
/*
2228
 *   update_status: update top textarea dynamically.
2229
 */
2230
function update_status($status) {
2231
	global $pkg_interface;
2232

    
2233
	if ($pkg_interface == "console") {
2234
		print ("{$status}");
2235
	}
2236

    
2237
	/* ensure that contents are written out */
2238
	ob_flush();
2239
}
2240

    
2241
/*
2242
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
2243
 */
2244
function update_progress_bar($percent, $first_time) {
2245
	global $pkg_interface;
2246
	if ($percent > 100) {
2247
		$percent = 1;
2248
	}
2249
	if ($pkg_interface <> "console") {
2250
		echo '<script type="text/javascript">';
2251
		echo "\n//<![CDATA[\n";
2252
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
2253
		echo "\n//]]>\n";
2254
		echo '</script>';
2255
	} else {
2256
		if (!($first_time)) {
2257
			echo "\x08\x08\x08\x08\x08";
2258
		}
2259
		echo sprintf("%4d%%", $percent);
2260
	}
2261
}
2262

    
2263
function update_alias_name($new_alias_name, $orig_alias_name) {
2264
	if (!$orig_alias_name) {
2265
		return;
2266
	}
2267

    
2268
	// Firewall rules
2269
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2270
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2271
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2272
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2273
	// NAT Rules
2274
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2275
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2276
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2277
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2278
	update_alias_names_upon_change(array('nat', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2279
	update_alias_names_upon_change(array('nat', 'rule'), array('local-port'), $new_alias_name, $orig_alias_name);
2280
	// NAT 1:1 Rules
2281
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('external'), $new_alias_name, $orig_alias_name);
2282
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2283
	update_alias_names_upon_change(array('nat', 'onetoone'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2284
	// NAT Outbound Rules
2285
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('source', 'network'), $new_alias_name, $orig_alias_name);
2286
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('sourceport'), $new_alias_name, $orig_alias_name);
2287
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2288
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('dstport'), $new_alias_name, $orig_alias_name);
2289
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2290
	// Alias in an alias
2291
	update_alias_names_upon_change(array('aliases', 'alias'), array('address'), $new_alias_name, $orig_alias_name);
2292
}
2293

    
2294
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2295
	global $g, $config, $pconfig, $debug;
2296
	if (!$origname) {
2297
		return;
2298
	}
2299

    
2300
	$sectionref = &$config;
2301
	foreach ($section as $sectionname) {
2302
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2303
			$sectionref = &$sectionref[$sectionname];
2304
		} else {
2305
			return;
2306
		}
2307
	}
2308

    
2309
	if ($debug) {
2310
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2311
		fwrite($fd, print_r($pconfig, true));
2312
	}
2313

    
2314
	if (is_array($sectionref)) {
2315
		foreach ($sectionref as $itemkey => $item) {
2316
			if ($debug) {
2317
				fwrite($fd, "$itemkey\n");
2318
			}
2319

    
2320
			$fieldfound = true;
2321
			$fieldref = &$sectionref[$itemkey];
2322
			foreach ($field as $fieldname) {
2323
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2324
					$fieldref = &$fieldref[$fieldname];
2325
				} else {
2326
					$fieldfound = false;
2327
					break;
2328
				}
2329
			}
2330
			if ($fieldfound && $fieldref == $origname) {
2331
				if ($debug) {
2332
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2333
				}
2334
				$fieldref = $new_alias_name;
2335
			}
2336
		}
2337
	}
2338

    
2339
	if ($debug) {
2340
		fclose($fd);
2341
	}
2342

    
2343
}
2344

    
2345
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2346
	/*
2347
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2348
	 * $type = if set to 'url' then subnets and ips will be returned,
2349
	 *         if set to 'url_ports' port-ranges and ports will be returned
2350
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2351
	 *
2352
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2353
	 */
2354

    
2355
	if (!file_exists($filename)) {
2356
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2357
		return null;
2358
	}
2359

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

    
2402
function update_alias_url_data() {
2403
	global $config, $g;
2404

    
2405
	$updated = false;
2406

    
2407
	/* item is a url type */
2408
	$lockkey = lock('aliasurl');
2409
	if (is_array($config['aliases']['alias'])) {
2410
		foreach ($config['aliases']['alias'] as $x => $alias) {
2411
			if (empty($alias['aliasurl'])) {
2412
				continue;
2413
			}
2414

    
2415
			$address = null;
2416
			foreach ($alias['aliasurl'] as $alias_url) {
2417
				/* fetch down and add in */
2418
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2419
				unlink($temp_filename);
2420
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2421
				mkdir($temp_filename);
2422
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2423
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2424
					continue;
2425
				}
2426

    
2427
				/* if the item is tar gzipped then extract */
2428
				if (stripos($alias_url, '.tgz')) {
2429
					if (!process_alias_tgz($temp_filename)) {
2430
						continue;
2431
					}
2432
				}
2433
				if (file_exists("{$temp_filename}/aliases")) {
2434
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2435
					mwexec("/bin/rm -rf {$temp_filename}");
2436
				}
2437
			}
2438
			if ($address != null) {
2439
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2440
				$updated = true;
2441
			}
2442
		}
2443
	}
2444
	unlock($lockkey);
2445

    
2446
	/* Report status to callers as well */
2447
	return $updated;
2448
}
2449

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

    
2480
	return true;
2481
}
2482

    
2483
function version_compare_dates($a, $b) {
2484
	$a_time = strtotime($a);
2485
	$b_time = strtotime($b);
2486

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

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

    
2571
		// First try to compare the numeric parts of the version string.
2572
		$v = version_compare_numeric($cur_num, $rem_num);
2573

    
2574
		// If the numeric parts are the same, compare the string parts.
2575
		if ($v == 0) {
2576
			return version_compare_string($cur_str, $rem_str);
2577
		}
2578
	}
2579
	return $v;
2580
}
2581
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2582
	global $g, $config;
2583

    
2584
	$urltable_prefix = "/var/db/aliastables/";
2585
	$urltable_filename = $urltable_prefix . $name . ".txt";
2586
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2587

    
2588
	// Make the aliases directory if it doesn't exist
2589
	if (!file_exists($urltable_prefix)) {
2590
		mkdir($urltable_prefix);
2591
	} elseif (!is_dir($urltable_prefix)) {
2592
		unlink($urltable_prefix);
2593
		mkdir($urltable_prefix);
2594
	}
2595

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

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

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

    
2610
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2611
			if ($type == "urltable_ports") {
2612
				$parsed_contents = group_ports($parsed_contents, true);
2613
			}
2614
			if (is_array($parsed_contents)) {
2615
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2616
			} else {
2617
				touch($urltable_filename);
2618
			}
2619

    
2620
			/* Remove existing archive and create an up to date archive if RAM disk is enabled. */
2621
			unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz");
2622
			if (isset($config['system']['use_mfs_tmpvar'])) {
2623
				mwexec("/usr/bin/tar -czf " . escapeshellarg("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz") . " -C / " . escapeshellarg($urltable_filename));
2624
			}
2625

    
2626
			unlink_if_exists($tmp_urltable_filename);
2627
		} else {
2628
			if (!$validateonly) {
2629
				touch($urltable_filename);
2630
			}
2631
			return false;
2632
		}
2633
		return true;
2634
	} else {
2635
		// File exists, and it doesn't need to be updated.
2636
		return -1;
2637
	}
2638
}
2639

    
2640
function get_include_contents($filename) {
2641
	if (is_file($filename)) {
2642
		ob_start();
2643
		include $filename;
2644
		$contents = ob_get_contents();
2645
		ob_end_clean();
2646
		return $contents;
2647
	}
2648
	return false;
2649
}
2650

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

    
2763
function get_country_name($country_code = "ALL") {
2764
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2765
		return "";
2766
	}
2767

    
2768
	$country_names_xml = "/usr/local/share/pfSense/iso_3166-1_list_en.xml";
2769
	$country_names_contents = file_get_contents($country_names_xml);
2770
	$country_names = xml2array($country_names_contents);
2771

    
2772
	if ($country_code == "ALL") {
2773
		$country_list = array();
2774
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2775
			$country_list[] = array(
2776
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2777
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2778
		}
2779
		return $country_list;
2780
	}
2781

    
2782
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2783
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2784
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2785
		}
2786
	}
2787
	return "";
2788
}
2789

    
2790
/* Return the list of country codes to be used on CAs and certs */
2791
function get_cert_country_codes() {
2792
	$countries = get_country_name();
2793

    
2794
	$country_codes = array();
2795
	foreach ($countries as $country) {
2796
		$country_codes[$country['code']] = $country['code'];
2797
	}
2798
	ksort($country_codes);
2799

    
2800
	/* Preserve historical order: None, US, CA, other countries */
2801
	$first_items[''] = gettext("None");
2802
	$first_items['US'] = $country_codes['US'];
2803
	$first_items['CA'] = $country_codes['CA'];
2804
	unset($country_codes['US']);
2805
	unset($country_codes['CA']);
2806

    
2807
	return array_merge($first_items, $country_codes);
2808
}
2809

    
2810
/* sort by interface only, retain the original order of rules that apply to
2811
   the same interface */
2812
function filter_rules_sort() {
2813
	global $config;
2814

    
2815
	init_config_arr(array('filter', 'rule'));
2816
	/* mark each rule with the sequence number (to retain the order while sorting) */
2817
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2818
		if (!is_array($config['filter']['rule'][$i])) {
2819
			$config['filter']['rule'][$i] = array();
2820
		}
2821
		$config['filter']['rule'][$i]['seq'] = $i;
2822
	}
2823

    
2824
	usort($config['filter']['rule'], "filter_rules_compare");
2825

    
2826
	/* strip the sequence numbers again */
2827
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2828
		unset($config['filter']['rule'][$i]['seq']);
2829
	}
2830
}
2831
function filter_rules_compare($a, $b) {
2832
	if (isset($a['floating']) && isset($b['floating'])) {
2833
		return $a['seq'] - $b['seq'];
2834
	} else if (isset($a['floating'])) {
2835
		return -1;
2836
	} else if (isset($b['floating'])) {
2837
		return 1;
2838
	} else if ($a['interface'] == $b['interface']) {
2839
		return $a['seq'] - $b['seq'];
2840
	} else {
2841
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2842
	}
2843
}
2844

    
2845
function generate_ipv6_from_mac($mac) {
2846
	$elements = explode(":", $mac);
2847
	if (count($elements) <> 6) {
2848
		return false;
2849
	}
2850

    
2851
	$i = 0;
2852
	$ipv6 = "fe80::";
2853
	foreach ($elements as $byte) {
2854
		if ($i == 0) {
2855
			$hexadecimal = substr($byte, 1, 2);
2856
			$bitmap = base_convert($hexadecimal, 16, 2);
2857
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2858
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2859
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2860
		}
2861
		$ipv6 .= $byte;
2862
		if ($i == 1) {
2863
			$ipv6 .= ":";
2864
		}
2865
		if ($i == 3) {
2866
			$ipv6 .= ":";
2867
		}
2868
		if ($i == 2) {
2869
			$ipv6 .= "ff:fe";
2870
		}
2871

    
2872
		$i++;
2873
	}
2874
	return $ipv6;
2875
}
2876

    
2877
/****f* pfsense-utils/load_mac_manufacturer_table
2878
 * NAME
2879
 *   load_mac_manufacturer_table
2880
 * INPUTS
2881
 *   none
2882
 * RESULT
2883
 *   returns associative array with MAC-Manufacturer pairs
2884
 ******/
2885
function load_mac_manufacturer_table() {
2886
	/* load MAC-Manufacture data from the file */
2887
	$macs = false;
2888
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2889
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2890
	}
2891
	if ($macs) {
2892
		foreach ($macs as $line) {
2893
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2894
				/* store values like this $mac_man['000C29']='VMware' */
2895
				$mac_man["$matches[1]"] = $matches[2];
2896
			}
2897
		}
2898
		return $mac_man;
2899
	} else {
2900
		return -1;
2901
	}
2902

    
2903
}
2904

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

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

    
2944
	$where_configured = array();
2945

    
2946
	$pos = strpos($ignore_if, '_virtualip');
2947
	if ($pos !== false) {
2948
		$ignore_vip_id = substr($ignore_if, $pos+10);
2949
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2950
	} else {
2951
		$ignore_vip_id = -1;
2952
		$ignore_vip_if = $ignore_if;
2953
	}
2954

    
2955
	$isipv6 = is_ipaddrv6($ipaddr);
2956

    
2957
	if ($isipv6) {
2958
		$ipaddr = text_to_compressed_ip6($ipaddr);
2959
	}
2960

    
2961
	if ($check_subnets) {
2962
		$cidrprefix = intval($cidrprefix);
2963
		if ($isipv6) {
2964
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2965
				$cidrprefix = 128;
2966
			}
2967
		} else {
2968
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2969
				$cidrprefix = 32;
2970
			}
2971
		}
2972
		$iflist = get_configured_interface_list();
2973
		foreach ($iflist as $if => $ifname) {
2974
			if ($ignore_if == $if) {
2975
				continue;
2976
			}
2977

    
2978
			if ($isipv6) {
2979
				$if_ipv6 = get_interface_ipv6($if);
2980
				$if_snbitsv6 = get_interface_subnetv6($if);
2981
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2982
					$where_entry = array();
2983
					$where_entry['if'] = $if;
2984
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2985
					$where_configured[] = $where_entry;
2986
				}
2987
			} else {
2988
				$if_ipv4 = get_interface_ip($if);
2989
				$if_snbitsv4 = get_interface_subnet($if);
2990
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
2991
					$where_entry = array();
2992
					$where_entry['if'] = $if;
2993
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
2994
					$where_configured[] = $where_entry;
2995
				}
2996
			}
2997
		}
2998
	} else {
2999
		if ($isipv6) {
3000
			$interface_list_ips = get_configured_ipv6_addresses();
3001
		} else {
3002
			$interface_list_ips = get_configured_ip_addresses();
3003
		}
3004

    
3005
		foreach ($interface_list_ips as $if => $ilips) {
3006
			if ($ignore_if == $if) {
3007
				continue;
3008
			}
3009
			if (strcasecmp($ipaddr, $ilips) == 0) {
3010
				$where_entry = array();
3011
				$where_entry['if'] = $if;
3012
				$where_entry['ip_or_subnet'] = $ilips;
3013
				$where_configured[] = $where_entry;
3014
			}
3015
		}
3016
	}
3017

    
3018
	if ($check_localip) {
3019
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, text_to_compressed_ip6($config['l2tp']['localip'])) == 0)) {
3020
			$where_entry = array();
3021
			$where_entry['if'] = 'l2tp';
3022
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
3023
			$where_configured[] = $where_entry;
3024
		}
3025
	}
3026

    
3027
	return $where_configured;
3028
}
3029

    
3030
/****f* pfsense-utils/pfSense_handle_custom_code
3031
 * NAME
3032
 *   pfSense_handle_custom_code
3033
 * INPUTS
3034
 *   directory name to process
3035
 * RESULT
3036
 *   globs the directory and includes the files
3037
 */
3038
function pfSense_handle_custom_code($src_dir) {
3039
	// Allow extending of the nat edit page and include custom input validation
3040
	if (is_dir("$src_dir")) {
3041
		$cf = glob($src_dir . "/*.inc");
3042
		foreach ($cf as $nf) {
3043
			if ($nf == "." || $nf == "..") {
3044
				continue;
3045
			}
3046
			// Include the extra handler
3047
			include_once("$nf");
3048
		}
3049
	}
3050
}
3051

    
3052
function set_language() {
3053
	global $config, $g;
3054

    
3055
	if (!empty($config['system']['language'])) {
3056
		$lang = $config['system']['language'];
3057
	} elseif (!empty($g['language'])) {
3058
		$lang = $g['language'];
3059
	}
3060
	$lang .= ".UTF-8";
3061

    
3062
	putenv("LANG={$lang}");
3063
	setlocale(LC_ALL, $lang);
3064
	textdomain("pfSense");
3065
	bindtextdomain("pfSense", "/usr/local/share/locale");
3066
	bind_textdomain_codeset("pfSense", $lang);
3067
}
3068

    
3069
function get_locale_list() {
3070
	$locales = array(
3071
		"bs" => gettext("Bosnian"),
3072
		"zh_CN" => gettext("Chinese"),
3073
		"zh_Hans_CN" => gettext("Chinese (Simplified, China)"),
3074
		"zh_Hans_HK" => gettext("Chinese (Simplified, Hong Kong SAR China)"),
3075
		"zh_Hant_TW" => gettext("Chinese (Traditional, Taiwan)"),
3076
		"nl" => gettext("Dutch"),
3077
		"en_US" => gettext("English"),
3078
		"fr" => gettext("French"),
3079
		"de_DE" => gettext("German (Germany)"),
3080
		"it" => gettext("Italian"),
3081
		"ko" => gettext("Korean"),
3082
		"nb" => gettext("Norwegian Bokmål"),
3083
		"pl" => gettext("Polish"),
3084
		"pt_PT" => gettext("Portuguese"),
3085
		"pt_BR" => gettext("Portuguese (Brazil)"),
3086
		"ru" => gettext("Russian"),
3087
		"es" => gettext("Spanish"),
3088
		"es_AR" => gettext("Spanish (Argentina)"),
3089
	);
3090

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

    
3095
	//asort($locales);
3096

    
3097
	return $locales;
3098
}
3099

    
3100
function return_hex_ipv4($ipv4) {
3101
	if (!is_ipaddrv4($ipv4)) {
3102
		return(false);
3103
	}
3104

    
3105
	/* we need the hex form of the interface IPv4 address */
3106
	$ip4arr = explode(".", $ipv4);
3107
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
3108
}
3109

    
3110
function convert_ipv6_to_128bit($ipv6) {
3111
	if (!is_ipaddrv6($ipv6)) {
3112
		return(false);
3113
	}
3114

    
3115
	$ip6arr = array();
3116
	$ip6prefix = Net_IPv6::uncompress($ipv6);
3117
	$ip6arr = explode(":", $ip6prefix);
3118
	/* binary presentation of the prefix for all 128 bits. */
3119
	$ip6prefixbin = "";
3120
	foreach ($ip6arr as $element) {
3121
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3122
	}
3123
	return($ip6prefixbin);
3124
}
3125

    
3126
function convert_128bit_to_ipv6($ip6bin) {
3127
	if (strlen($ip6bin) <> 128) {
3128
		return(false);
3129
	}
3130

    
3131
	$ip6arr = array();
3132
	$ip6binarr = array();
3133
	$ip6binarr = str_split($ip6bin, 16);
3134
	foreach ($ip6binarr as $binpart) {
3135
		$ip6arr[] = dechex(bindec($binpart));
3136
	}
3137
	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
3138

    
3139
	return($ip6addr);
3140
}
3141

    
3142

    
3143
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3144
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3145
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3146
/* 6to4 is 16 bits, e.g. 65535 */
3147
function calculate_ipv6_delegation_length($if) {
3148
	global $config;
3149

    
3150
	if (!is_array($config['interfaces'][$if])) {
3151
		return false;
3152
	}
3153

    
3154
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3155
		case "6to4":
3156
			$pdlen = 16;
3157
			break;
3158
		case "6rd":
3159
			$rd6cfg = $config['interfaces'][$if];
3160
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3161
			$pdlen = (64 - ((int) $rd6plen[1] + (32 - (int) $rd6cfg['prefix-6rd-v4plen'])));
3162
			break;
3163
		case "dhcp6":
3164
			$dhcp6cfg = $config['interfaces'][$if];
3165
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3166
			break;
3167
		default:
3168
			$pdlen = 0;
3169
			break;
3170
	}
3171
	return($pdlen);
3172
}
3173

    
3174
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3175
	$prefix = Net_IPv6::uncompress($prefix, true);
3176
	$suffix = Net_IPv6::uncompress($suffix, true);
3177

    
3178
	/*
3179
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3180
	 *                ^^^^ ^
3181
	 *                |||| \-> 64
3182
	 *                |||\---> 63, 62, 61, 60
3183
	 *                ||\----> 56
3184
	 *                |\-----> 52
3185
	 *                \------> 48
3186
	 */
3187

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

    
3219
	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
3220
	    substr($suffix, $prefix_len));
3221
}
3222

    
3223
function dhcpv6_pd_str_help($pdlen) {
3224
	$result = '';
3225

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

    
3258
	return $result;
3259
}
3260

    
3261
function huawei_rssi_to_string($rssi) {
3262
	$dbm = array();
3263
	$i = 0;
3264
	$dbstart = -113;
3265
	while ($i < 32) {
3266
		$dbm[$i] = $dbstart + ($i * 2);
3267
		$i++;
3268
	}
3269
	$percent = round(($rssi / 31) * 100);
3270
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3271
	return $string;
3272
}
3273

    
3274
function huawei_mode_to_string($mode, $submode) {
3275
	$modes[0] = gettext("None");
3276
	$modes[1] = "AMPS";
3277
	$modes[2] = "CDMA";
3278
	$modes[3] = "GSM/GPRS";
3279
	$modes[4] = "HDR";
3280
	$modes[5] = "WCDMA";
3281
	$modes[6] = "GPS";
3282

    
3283
	$submodes[0] = gettext("No Service");
3284
	$submodes[1] = "GSM";
3285
	$submodes[2] = "GPRS";
3286
	$submodes[3] = "EDGE";
3287
	$submodes[4] = "WCDMA";
3288
	$submodes[5] = "HSDPA";
3289
	$submodes[6] = "HSUPA";
3290
	$submodes[7] = "HSDPA+HSUPA";
3291
	$submodes[8] = "TD-SCDMA";
3292
	$submodes[9] = "HSPA+";
3293
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3294
	return $string;
3295
}
3296

    
3297
function huawei_service_to_string($state) {
3298
	$modes[0] = gettext("No Service");
3299
	$modes[1] = gettext("Restricted Service");
3300
	$modes[2] = gettext("Valid Service");
3301
	$modes[3] = gettext("Restricted Regional Service");
3302
	$modes[4] = gettext("Powersaving Service");
3303
	$modes[255] = gettext("Unknown Service");
3304
	$string = $modes[$state];
3305
	return $string;
3306
}
3307

    
3308
function huawei_simstate_to_string($state) {
3309
	$modes[0] = gettext("Invalid SIM/locked State");
3310
	$modes[1] = gettext("Valid SIM State");
3311
	$modes[2] = gettext("Invalid SIM CS State");
3312
	$modes[3] = gettext("Invalid SIM PS State");
3313
	$modes[4] = gettext("Invalid SIM CS/PS State");
3314
	$modes[255] = gettext("Missing SIM State");
3315
	$string = $modes[$state];
3316
	return $string;
3317
}
3318

    
3319
function zte_rssi_to_string($rssi) {
3320
	return huawei_rssi_to_string($rssi);
3321
}
3322

    
3323
function zte_mode_to_string($mode, $submode) {
3324
	$modes[0] = gettext("No Service");
3325
	$modes[1] = gettext("Limited Service");
3326
	$modes[2] = "GPRS";
3327
	$modes[3] = "GSM";
3328
	$modes[4] = "UMTS";
3329
	$modes[5] = "EDGE";
3330
	$modes[6] = "HSDPA";
3331

    
3332
	$submodes[0] = "CS_ONLY";
3333
	$submodes[1] = "PS_ONLY";
3334
	$submodes[2] = "CS_PS";
3335
	$submodes[3] = "CAMPED";
3336
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3337
	return $string;
3338
}
3339

    
3340
function zte_service_to_string($service) {
3341
	$modes[0] = gettext("Initializing Service");
3342
	$modes[1] = gettext("Network Lock error Service");
3343
	$modes[2] = gettext("Network Locked Service");
3344
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3345
	$string = $modes[$service];
3346
	return $string;
3347
}
3348

    
3349
function zte_simstate_to_string($state) {
3350
	$modes[0] = gettext("No action State");
3351
	$modes[1] = gettext("Network lock State");
3352
	$modes[2] = gettext("(U)SIM card lock State");
3353
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3354
	$string = $modes[$state];
3355
	return $string;
3356
}
3357

    
3358
function get_configured_pppoe_server_interfaces() {
3359
	global $config;
3360
	$iflist = array();
3361
	if (is_array($config['pppoes']['pppoe'])) {
3362
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3363
			if ($pppoe['mode'] == "server") {
3364
				$int = "poes". $pppoe['pppoeid'];
3365
				$iflist[$int] = strtoupper($int);
3366
			}
3367
		}
3368
	}
3369
	return $iflist;
3370
}
3371

    
3372
function get_pppoes_child_interfaces($ifpattern) {
3373
	$if_arr = array();
3374
	if ($ifpattern == "") {
3375
		return;
3376
	}
3377

    
3378
	exec("/sbin/ifconfig", $out, $ret);
3379
	foreach ($out as $line) {
3380
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3381
			$if_arr[] = $match[1];
3382
		}
3383
	}
3384
	return $if_arr;
3385

    
3386
}
3387

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

    
3424
// Convert IPv6 addresses to lower case
3425
function addrtolower($ip) {
3426
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3427
		return(strtolower($ip));
3428
	} else {
3429
		return($ip);
3430
	}
3431
}
3432

    
3433
function compare_by_name($a, $b) {
3434
	return strcasecmp($a['name'], $b['name']);
3435
}
3436

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

    
3468
?>
(37-37/59)