Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
217
	$csslist = get_css_files();
218

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
770
	return "";
771
}
772

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

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

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

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

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

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

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

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

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

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

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

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

    
883
	return false;
884
}
885

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1210
	return ($data);
1211
}
1212

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

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

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

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

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

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

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

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

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

    
1306
	safe_write_file($loader_conf_file, $data);
1307

    
1308
	/* Filter loader.conf.local to avoid duplicate settings. */
1309
	$loader_conf_file = "{$path}/boot/loader.conf.local";
1310
	$data = load_loader_conf($loader_conf_file, true);
1311
	if (empty($data)) {
1312
		@unlink($loader_conf_file);
1313
	} else {
1314
		safe_write_file($loader_conf_file, $data);
1315
	}
1316

    
1317
}
1318

    
1319
function setup_serial_port($when = "save", $path = "") {
1320
	global $config;
1321
	$ttys_file = "{$path}/etc/ttys";
1322

    
1323
	/* Update the loader settings. */
1324
	setup_loader_settings($path, ($when == "upgrade"));
1325

    
1326
	$ttys = file_get_contents($ttys_file);
1327
	$ttys_split = explode("\n", $ttys);
1328

    
1329
	$data = array();
1330

    
1331
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1332

    
1333
	if (isset($config['system']['disableconsolemenu'])) {
1334
		$console_type = 'Pc';
1335
		$serial_type = '3wire';
1336
	} else {
1337
		$console_type = 'al.Pc';
1338
		$serial_type = 'al.3wire';
1339
	}
1340

    
1341
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1342
	$ttyv0_line =
1343
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\txterm\ton\tsecure";
1344
	$ttyu_line =
1345
	    "\"/usr/libexec/getty {$serial_type}\"\tvt100\t{$on_off}\tsecure";
1346

    
1347
	$found = array();
1348

    
1349
	foreach ($ttys_split as $tty) {
1350
		/* Ignore blank lines */
1351
		if (empty($tty)) {
1352
			continue;
1353
		}
1354

    
1355
		if (stristr($tty, "ttyv0")) {
1356
			$found['ttyv0'] = 1;
1357
			$data[] = $ttyv0_line;
1358
		} elseif (stristr($tty, "ttyu")) {
1359
			$ttyn = substr($tty, 0, 5);
1360
			$found[$ttyn] = 1;
1361
			$data[] = "{$ttyn}\t{$ttyu_line}";
1362
		} elseif (substr($tty, 0, 7) == 'console') {
1363
			$found['console'] = 1;
1364
			$data[] = $tty;
1365
		} else {
1366
			$data[] = $tty;
1367
		}
1368
	}
1369
	unset($on_off, $console_type, $serial_type);
1370

    
1371
	/* Detect missing main lines on original file and try to rebuild it */
1372
	$items = array(
1373
		'console',
1374
		'ttyv0',
1375
		'ttyu0',
1376
		'ttyu1',
1377
		'ttyu2',
1378
		'ttyu3'
1379
	);
1380

    
1381
	foreach ($items as $item) {
1382
		if (isset($found[$item])) {
1383
			continue;
1384
		}
1385

    
1386
		if ($item == 'console') {
1387
			$data[] = $console_line;
1388
		} elseif ($item == 'ttyv0') {
1389
			$data[] = $ttyv0_line;
1390
		} else {
1391
			$data[] = "{$item}\t{$ttyu_line}";
1392
		}
1393
	}
1394

    
1395
	safe_write_file($ttys_file, $data);
1396

    
1397
	unset($ttys, $ttys_file, $ttys_split, $data);
1398

    
1399
	if ($when != "upgrade") {
1400
		reload_ttys();
1401
	}
1402

    
1403
	return;
1404
}
1405

    
1406
function is_serial_enabled() {
1407
	global $g, $config;
1408

    
1409
	if (!isset($g['enableserial_force']) &&
1410
	    !isset($config['system']['enableserial'])) {
1411
		return false;
1412
	}
1413

    
1414
	return true;
1415
}
1416

    
1417
function reload_ttys() {
1418
	// Send a HUP signal to init will make it reload /etc/ttys
1419
	posix_kill(1, SIGHUP);
1420
}
1421

    
1422
function print_value_list($list, $count = 10, $separator = ",") {
1423
	$list = implode($separator, array_slice($list, 0, $count));
1424
	if (count($list) < $count) {
1425
		$list .= ".";
1426
	} else {
1427
		$list .= "...";
1428
	}
1429
	return $list;
1430
}
1431

    
1432
/* DHCP enabled on any interfaces? */
1433
function is_dhcp_server_enabled() {
1434
	global $config;
1435

    
1436
	if (!is_array($config['dhcpd'])) {
1437
		return false;
1438
	}
1439

    
1440
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1441
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1442
			return true;
1443
		}
1444
	}
1445

    
1446
	return false;
1447
}
1448

    
1449
/* DHCP enabled on any interfaces? */
1450
function is_dhcpv6_server_enabled() {
1451
	global $config;
1452

    
1453
	if (is_array($config['interfaces'])) {
1454
		foreach ($config['interfaces'] as $ifcfg) {
1455
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1456
				return true;
1457
			}
1458
		}
1459
	}
1460

    
1461
	if (!is_array($config['dhcpdv6'])) {
1462
		return false;
1463
	}
1464

    
1465
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1466
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1467
			return true;
1468
		}
1469
	}
1470

    
1471
	return false;
1472
}
1473

    
1474
/* radvd enabled on any interfaces? */
1475
function is_radvd_enabled() {
1476
	global $config;
1477

    
1478
	if (!is_array($config['dhcpdv6'])) {
1479
		$config['dhcpdv6'] = array();
1480
	}
1481

    
1482
	$dhcpdv6cfg = $config['dhcpdv6'];
1483
	$Iflist = get_configured_interface_list();
1484

    
1485
	/* handle manually configured DHCP6 server settings first */
1486
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1487
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1488
			continue;
1489
		}
1490

    
1491
		if (!isset($dhcpv6ifconf['ramode'])) {
1492
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1493
		}
1494

    
1495
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1496
			continue;
1497
		}
1498

    
1499
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1500
		if (!is_ipaddrv6($ifcfgipv6)) {
1501
			continue;
1502
		}
1503

    
1504
		return true;
1505
	}
1506

    
1507
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1508
	foreach ($Iflist as $if => $ifdescr) {
1509
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1510
			continue;
1511
		}
1512
		if (!isset($config['interfaces'][$if]['enable'])) {
1513
			continue;
1514
		}
1515

    
1516
		$ifcfgipv6 = get_interface_ipv6($if);
1517
		if (!is_ipaddrv6($ifcfgipv6)) {
1518
			continue;
1519
		}
1520

    
1521
		$ifcfgsnv6 = get_interface_subnetv6($if);
1522
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1523

    
1524
		if (!is_ipaddrv6($subnetv6)) {
1525
			continue;
1526
		}
1527

    
1528
		return true;
1529
	}
1530

    
1531
	return false;
1532
}
1533

    
1534
/* Any PPPoE servers enabled? */
1535
function is_pppoe_server_enabled() {
1536
	global $config;
1537

    
1538
	$pppoeenable = false;
1539

    
1540
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1541
		return false;
1542
	}
1543

    
1544
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1545
		if ($pppoes['mode'] == 'server') {
1546
			$pppoeenable = true;
1547
		}
1548
	}
1549

    
1550
	return $pppoeenable;
1551
}
1552

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

    
1567
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1568

    
1569
function get_ppp_uptime($port) {
1570
	if (file_exists("/conf/{$port}.log")) {
1571
		$saved_time = file_get_contents("/conf/{$port}.log");
1572
		$uptime_data = explode("\n", $saved_time);
1573
		$sec = 0;
1574
		foreach ($uptime_data as $upt) {
1575
			$sec += substr($upt, 1 + strpos($upt, " "));
1576
		}
1577
		return convert_seconds_to_dhms($sec);
1578
	} else {
1579
		$total_time = gettext("No history data found!");
1580
		return $total_time;
1581
	}
1582
}
1583

    
1584
//returns interface information
1585
function get_interface_info($ifdescr) {
1586
	global $config, $g;
1587

    
1588
	$ifinfo = array();
1589
	if (empty($config['interfaces'][$ifdescr])) {
1590
		return;
1591
	}
1592
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1593
	$ifinfo['enable'] = isset($config['interfaces'][$ifdescr]['enable']);
1594
	$ifinfo['if'] = get_real_interface($ifdescr);
1595

    
1596
	$chkif = $ifinfo['if'];
1597
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1598
	$ifinfo['status'] = $ifinfotmp['status'];
1599
	if (empty($ifinfo['status'])) {
1600
		$ifinfo['status'] = "down";
1601
	}
1602
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1603
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1604
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1605
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1606
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1607
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1608
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1609
	if (isset($ifinfotmp['link0'])) {
1610
		$link0 = "down";
1611
	}
1612
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1613
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1614
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1615
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1616
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1617
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1618

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

    
1639
	/* Block */
1640
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1641
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1642
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1643
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1644
	$in4_block = $pf_in4_block[5];
1645
	$out4_block = $pf_out4_block[5];
1646
	$in4_block_packets = $pf_in4_block[3];
1647
	$out4_block_packets = $pf_out4_block[3];
1648
	$in6_block = $pf_in6_block[5];
1649
	$out6_block = $pf_out6_block[5];
1650
	$in6_block_packets = $pf_in6_block[3];
1651
	$out6_block_packets = $pf_out6_block[3];
1652
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1653
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1654
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1655
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1656

    
1657
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1658
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1659
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1660
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1661

    
1662
	$ifconfiginfo = "";
1663
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1664
	switch ($link_type) {
1665
		/* DHCP? -> see if dhclient is up */
1666
		case "dhcp":
1667
			/* see if dhclient is up */
1668
			if (find_dhclient_process($ifinfo['if']) != 0) {
1669
				$ifinfo['dhcplink'] = "up";
1670
			} else {
1671
				$ifinfo['dhcplink'] = "down";
1672
			}
1673

    
1674
			break;
1675
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1676
		case "pppoe":
1677
		case "pptp":
1678
		case "l2tp":
1679
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1680
				/* get PPPoE link status for dial on demand */
1681
				$ifinfo["{$link_type}link"] = "up";
1682
			} else {
1683
				$ifinfo["{$link_type}link"] = "down";
1684
			}
1685

    
1686
			break;
1687
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1688
		case "ppp":
1689
			if ($ifinfo['status'] == "up") {
1690
				$ifinfo['ppplink'] = "up";
1691
			} else {
1692
				$ifinfo['ppplink'] = "down" ;
1693
			}
1694

    
1695
			if (empty($ifinfo['status'])) {
1696
				$ifinfo['status'] = "down";
1697
			}
1698

    
1699
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1700
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1701
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1702
						break;
1703
					}
1704
				}
1705
			}
1706
			$dev = $ppp['ports'];
1707
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1708
				break;
1709
			}
1710
			if (!file_exists($dev)) {
1711
				$ifinfo['nodevice'] = 1;
1712
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1713
			}
1714

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

    
1750
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1751
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1752
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1753
	}
1754

    
1755
	if ($ifinfo['status'] == "up") {
1756
		/* try to determine media with ifconfig */
1757
		unset($ifconfiginfo);
1758
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1759
		$wifconfiginfo = array();
1760
		if (is_interface_wireless($ifdescr)) {
1761
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1762
			array_shift($wifconfiginfo);
1763
		}
1764
		$matches = "";
1765
		foreach ($ifconfiginfo as $ici) {
1766

    
1767
			/* don't list media/speed for wireless cards, as it always
1768
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1769
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1770
				$ifinfo['media'] = $matches[1];
1771
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1772
				$ifinfo['media'] = $matches[1];
1773
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1774
				$ifinfo['media'] = $matches[1];
1775
			}
1776

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

    
1822
	$bridge = "";
1823
	$bridge = link_interface_to_bridge($ifdescr);
1824
	if ($bridge) {
1825
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1826
		if (stristr($bridge_text, "blocking") <> false) {
1827
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1828
			$ifinfo['bridgeint'] = $bridge;
1829
		} else if (stristr($bridge_text, "learning") <> false) {
1830
			$ifinfo['bridge'] = gettext("learning");
1831
			$ifinfo['bridgeint'] = $bridge;
1832
		} else if (stristr($bridge_text, "forwarding") <> false) {
1833
			$ifinfo['bridge'] = gettext("forwarding");
1834
			$ifinfo['bridgeint'] = $bridge;
1835
		}
1836
	}
1837

    
1838
	return $ifinfo;
1839
}
1840

    
1841
//returns cpu speed of processor. Good for determining capabilities of machine
1842
function get_cpu_speed() {
1843
	return get_single_sysctl("hw.clockrate");
1844
}
1845

    
1846
function get_uptime_sec() {
1847
	$boottime = "";
1848
	$matches = "";
1849
	$boottime = get_single_sysctl("kern.boottime");
1850
	preg_match("/sec = (\d+)/", $boottime, $matches);
1851
	$boottime = $matches[1];
1852
	if (intval($boottime) == 0) {
1853
		return 0;
1854
	}
1855

    
1856
	$uptime = time() - $boottime;
1857
	return $uptime;
1858
}
1859

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

    
1893
function is_fqdn($fqdn) {
1894
	$hostname = false;
1895
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1896
		$hostname = true;
1897
	}
1898
	if (preg_match("/\.\./", $fqdn)) {
1899
		$hostname = false;
1900
	}
1901
	if (preg_match("/^\./i", $fqdn)) {
1902
		$hostname = false;
1903
	}
1904
	if (preg_match("/\//i", $fqdn)) {
1905
		$hostname = false;
1906
	}
1907
	return($hostname);
1908
}
1909

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

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

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

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

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

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

    
1982
	$enabled_modules = explode('_', $config['system']['crypto_hardware']);
1983

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

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

    
2002
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
2003
		return false;
2004
	}
2005

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

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

    
2024
	if ($rc != 0 || !isset($output[0])) {
2025
		return false;
2026
	}
2027

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

    
2034
	return false;
2035
}
2036

    
2037
function get_freebsd_version() {
2038
	$version = explode(".", php_uname("r"));
2039
	return $version[0];
2040
}
2041

    
2042
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
2043
	global $config, $g;
2044

    
2045
	$fp = fopen($destination, "wb");
2046

    
2047
	if (!$fp) {
2048
		return false;
2049
	}
2050

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

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

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

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

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

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

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

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

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

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

    
2230
/*
2231
 *   update_status: update top textarea dynamically.
2232
 */
2233
function update_status($status) {
2234
	global $pkg_interface;
2235

    
2236
	if ($pkg_interface == "console") {
2237
		print ("{$status}");
2238
	}
2239

    
2240
	/* ensure that contents are written out */
2241
	ob_flush();
2242
}
2243

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

    
2266
function update_alias_name($new_alias_name, $orig_alias_name) {
2267
	if (!$orig_alias_name) {
2268
		return;
2269
	}
2270

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

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

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

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

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

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

    
2342
	if ($debug) {
2343
		fclose($fd);
2344
	}
2345

    
2346
}
2347

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

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

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

    
2405
function update_alias_url_data() {
2406
	global $config, $g;
2407

    
2408
	$updated = false;
2409

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

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

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

    
2449
	/* Report status to callers as well */
2450
	return $updated;
2451
}
2452

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

    
2483
	return true;
2484
}
2485

    
2486
function version_compare_dates($a, $b) {
2487
	$a_time = strtotime($a);
2488
	$b_time = strtotime($b);
2489

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

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

    
2574
		// First try to compare the numeric parts of the version string.
2575
		$v = version_compare_numeric($cur_num, $rem_num);
2576

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

    
2587
	$urltable_prefix = "/var/db/aliastables/";
2588
	$urltable_filename = $urltable_prefix . $name . ".txt";
2589
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2590

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

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

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

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

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

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

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

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

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

    
2766
function get_country_name($country_code = "ALL") {
2767
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2768
		return "";
2769
	}
2770

    
2771
	$country_names_xml = "/usr/local/share/pfSense/iso_3166-1_list_en.xml";
2772
	$country_names_contents = file_get_contents($country_names_xml);
2773
	$country_names = xml2array($country_names_contents);
2774

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

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

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

    
2797
	$country_codes = array();
2798
	foreach ($countries as $country) {
2799
		$country_codes[$country['code']] = $country['code'];
2800
	}
2801
	ksort($country_codes);
2802

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

    
2810
	return array_merge($first_items, $country_codes);
2811
}
2812

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

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

    
2827
	usort($config['filter']['rule'], "filter_rules_compare");
2828

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

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

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

    
2875
		$i++;
2876
	}
2877
	return $ipv6;
2878
}
2879

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

    
2906
}
2907

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

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

    
2947
	$where_configured = array();
2948

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

    
2958
	$isipv6 = is_ipaddrv6($ipaddr);
2959

    
2960
	if ($isipv6) {
2961
		$ipaddr = text_to_compressed_ip6($ipaddr);
2962
	}
2963

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

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

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

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

    
3030
	return $where_configured;
3031
}
3032

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

    
3055
function set_language() {
3056
	global $config, $g;
3057

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

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

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

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

    
3097
	//asort($locales);
3098

    
3099
	return $locales;
3100
}
3101

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

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

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

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

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

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

    
3141
	return($ip6addr);
3142
}
3143

    
3144

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

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

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

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

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

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

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

    
3225
function dhcpv6_pd_str_help($pdlen) {
3226
	$result = '';
3227

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

    
3260
	return $result;
3261
}
3262

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

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

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

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

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

    
3321
function zte_rssi_to_string($rssi) {
3322
	return huawei_rssi_to_string($rssi);
3323
}
3324

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

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

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

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

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

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

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

    
3388
}
3389

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

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

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

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

    
3470
?>
(38-38/60)