Project

General

Profile

Download (93.8 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-2018 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
	$a_vip = &$config['virtualip']['vip'];
811
	foreach ($a_vip as $vipent) {
812
		if ($vipent['advskew'] <> "") {
813
			$processed_skew = 1;
814
			$vipent['advskew'] = $vipent['advskew']+1;
815
		}
816
	}
817
	if ($processed_skew == 1) {
818
		write_config(gettext("After synch increase advertising skew"));
819
	}
820
}
821

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

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

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

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

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

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

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

    
882
	return false;
883
}
884

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

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

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

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

    
933
	@unlink($g['tmp_path'] . "/tmpxml");
934
	if ($section_xml === -1) {
935
		return false;
936
	}
937
	$config[$section_name] = &$section_xml;
938
	if (file_exists("{$g['tmp_path']}/config.cache")) {
939
		unlink("{$g['tmp_path']}/config.cache");
940
	}
941
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
942
	disable_security_checks();
943
	return true;
944
}
945

    
946
/*
947
 *  merge_config_section($section_name, new_contents):   restore a configuration section,
948
 *                                                  and write the configuration out
949
 *                                                  to disk/cf.  But preserve the prior
950
 * 													structure if needed
951
 */
952
function merge_config_section($section_name, $new_contents) {
953
	global $config;
954
	$fname = get_tmp_filename();
955
	$fout = fopen($fname, "w");
956
	fwrite($fout, $new_contents);
957
	fclose($fout);
958
	$section_xml = parse_xml_config($fname, $section_name);
959
	$config[$section_name] = $section_xml;
960
	unlink($fname);
961
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
962
	disable_security_checks();
963
	return;
964
}
965

    
966
/*
967
 * rmdir_recursive($path, $follow_links=false)
968
 * Recursively remove a directory tree (rm -rf path)
969
 * This is for directories _only_
970
 */
971
function rmdir_recursive($path, $follow_links=false) {
972
	$to_do = glob($path);
973
	if (!is_array($to_do)) {
974
		$to_do = array($to_do);
975
	}
976
	foreach ($to_do as $workingdir) { // Handle wildcards by foreaching.
977
		if (file_exists($workingdir)) {
978
			if (is_dir($workingdir)) {
979
				$dir = opendir($workingdir);
980
				while ($entry = readdir($dir)) {
981
					if (is_file("$workingdir/$entry") || ((!$follow_links) && is_link("$workingdir/$entry"))) {
982
						unlink("$workingdir/$entry");
983
					} elseif (is_dir("$workingdir/$entry") && $entry != '.' && $entry != '..') {
984
						rmdir_recursive("$workingdir/$entry");
985
					}
986
				}
987
				closedir($dir);
988
				rmdir($workingdir);
989
			} elseif (is_file($workingdir)) {
990
				unlink($workingdir);
991
			}
992
		}
993
	}
994
	return;
995
}
996

    
997
/*
998
 * host_firmware_version(): Return the versions used in this install
999
 */
1000
function host_firmware_version($tocheck = "") {
1001
	global $g, $config;
1002

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

    
1005
	return array(
1006
		"firmware" => array("version" => $g['product_version']),
1007
		"kernel"   => array("version" => $os_version),
1008
		"base"     => array("version" => $os_version),
1009
		"platform" => $g['platform'],
1010
		"config_version" => $config['version']
1011
	);
1012
}
1013

    
1014
function get_disk_info() {
1015
	$diskout = "";
1016
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
1017
	return explode(' ', $diskout[0]);
1018
}
1019

    
1020
/****f* pfsense-utils/strncpy
1021
 * NAME
1022
 *   strncpy - copy strings
1023
 * INPUTS
1024
 *   &$dst, $src, $length
1025
 * RESULT
1026
 *   none
1027
 ******/
1028
function strncpy(&$dst, $src, $length) {
1029
	if (strlen($src) > $length) {
1030
		$dst = substr($src, 0, $length);
1031
	} else {
1032
		$dst = $src;
1033
	}
1034
}
1035

    
1036
/****f* pfsense-utils/reload_interfaces_sync
1037
 * NAME
1038
 *   reload_interfaces - reload all interfaces
1039
 * INPUTS
1040
 *   none
1041
 * RESULT
1042
 *   none
1043
 ******/
1044
function reload_interfaces_sync() {
1045
	global $config, $g;
1046

    
1047
	if ($g['debug']) {
1048
		log_error(gettext("reload_interfaces_sync() is starting."));
1049
	}
1050

    
1051
	/* parse config.xml again */
1052
	$config = parse_config(true);
1053

    
1054
	/* enable routing */
1055
	system_routing_enable();
1056
	if ($g['debug']) {
1057
		log_error(gettext("Enabling system routing"));
1058
	}
1059

    
1060
	if ($g['debug']) {
1061
		log_error(gettext("Cleaning up Interfaces"));
1062
	}
1063

    
1064
	/* set up interfaces */
1065
	interfaces_configure();
1066
}
1067

    
1068
/****f* pfsense-utils/reload_all
1069
 * NAME
1070
 *   reload_all - triggers a reload of all settings
1071
 *   * INPUTS
1072
 *   none
1073
 * RESULT
1074
 *   none
1075
 ******/
1076
function reload_all() {
1077
	send_event("service reload all");
1078
}
1079

    
1080
/****f* pfsense-utils/reload_interfaces
1081
 * NAME
1082
 *   reload_interfaces - triggers a reload of all interfaces
1083
 * INPUTS
1084
 *   none
1085
 * RESULT
1086
 *   none
1087
 ******/
1088
function reload_interfaces() {
1089
	send_event("interface all reload");
1090
}
1091

    
1092
/****f* pfsense-utils/reload_all_sync
1093
 * NAME
1094
 *   reload_all - reload all settings
1095
 *   * INPUTS
1096
 *   none
1097
 * RESULT
1098
 *   none
1099
 ******/
1100
function reload_all_sync() {
1101
	global $config, $g;
1102

    
1103
	/* parse config.xml again */
1104
	$config = parse_config(true);
1105

    
1106
	/* set up our timezone */
1107
	system_timezone_configure();
1108

    
1109
	/* set up our hostname */
1110
	system_hostname_configure();
1111

    
1112
	/* make hosts file */
1113
	system_hosts_generate();
1114

    
1115
	/* generate resolv.conf */
1116
	system_resolvconf_generate();
1117

    
1118
	/* enable routing */
1119
	system_routing_enable();
1120

    
1121
	/* set up interfaces */
1122
	interfaces_configure();
1123

    
1124
	/* start dyndns service */
1125
	services_dyndns_configure();
1126

    
1127
	/* configure cron service */
1128
	configure_cron();
1129

    
1130
	/* start the NTP client */
1131
	system_ntp_configure();
1132

    
1133
	/* sync pw database */
1134
	unlink_if_exists("/etc/spwd.db.tmp");
1135
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
1136

    
1137
	/* restart sshd */
1138
	send_event("service restart sshd");
1139

    
1140
	/* restart webConfigurator if needed */
1141
	send_event("service restart webgui");
1142
}
1143

    
1144
function load_loader_conf($loader_conf = NULL, $local = false) {
1145

    
1146
	if ($loader_conf == NULL) {
1147
		return (NULL);
1148
	}
1149
	if (file_exists($loader_conf)) {
1150
		$input = file_get_contents($loader_conf);
1151
	} else {
1152
		$input = "";
1153
	}
1154

    
1155
	$input_split = explode("\n", $input);
1156

    
1157
	/*
1158
	 * Loop through and only add lines that are not empty and not
1159
	 * managed by us.
1160
	 */
1161
	$data = array();
1162
	/* These values should be removed from loader.conf and loader.conf.local
1163
	 * As they will be replaced when necessary. */
1164
	$remove = array("hw.usb.no_pf", "hint.mdio.0.at", "hint.e6000sw.0",
1165
	    "vm.pmap.pti");
1166
	if (!$local) {
1167
		/* These values should only be filtered in loader.conf, not .local */
1168
		$remove = array_merge($remove,
1169
		    array("autoboot_delay", "console", "comconsole_speed",
1170
		    "boot_multicons", "boot_serial", "hint.uart.0.flags",
1171
		    "hint.uart.1.flags"));
1172
	}
1173
	foreach ($input_split as $line) {
1174
		if (empty($line)) {
1175
			continue;
1176
		}
1177
		list($name, $value) = explode('=', $line, 2);
1178
		if (!in_array(trim($name), $remove)) {
1179
			$data[] = $line;
1180
		}
1181
	}
1182

    
1183
	return ($data);
1184
}
1185

    
1186
function setup_loader_settings($path = "", $upgrade = false) {
1187
	global $g, $config;
1188

    
1189
	$boot_config_file = "{$path}/boot.config";
1190
	$loader_conf_file = "{$path}/boot/loader.conf";
1191

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

    
1194
	$vga_only = false;
1195
	$hdmi_only = false;
1196
	$serial_only = false;
1197
	$specific_platform = system_identify_specific_platform();
1198
	if ($specific_platform['name'] == 'XG-1540') {
1199
		$vga_only = true;
1200
	} elseif ($specific_platform['name'] == 'Turbot Dual-E') {
1201
		$hdmi_only = true;
1202
	} elseif ($specific_platform['name'] == 'RCC-VE' ||
1203
	    $specific_platform['name'] == 'RCC' ||
1204
	    $specific_platform['name'] == 'SG-2220' ||
1205
	    $specific_platform['name'] == 'apu2') {
1206
		$serial_only = true;
1207
	}
1208

    
1209
	/* Serial console - write out /boot.config */
1210
	if (file_exists($boot_config_file)) {
1211
		$boot_config = file_get_contents($boot_config_file);
1212
	} else {
1213
		$boot_config = "";
1214
	}
1215
	$boot_config_split = explode("\n", $boot_config);
1216
	$data = array();
1217
	foreach ($boot_config_split as $bcs) {
1218
		/* Ignore -D and -h lines now */
1219
		if (!empty($bcs) && !stristr($bcs, "-D") &&
1220
		    !stristr($bcs, "-h")) {
1221
			$data[] = $bcs;
1222
		}
1223
	}
1224
	if ($serial_only === true) {
1225
		$data[] = "-S{$serialspeed} -h";
1226
	} elseif (is_serial_enabled()) {
1227
		$data[] = "-S{$serialspeed} -D";
1228
	}
1229

    
1230
	if (empty($data)) {
1231
		@unlink($boot_conf_file);
1232
	} else {
1233
		safe_write_file($boot_config_file, $data);
1234
	}
1235
	unset($data, $boot_config, $boot_config_file, $boot_config_split);
1236

    
1237
	/* Serial console - write out /boot/loader.conf */
1238
	if ($upgrade) {
1239
		system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1240
	}
1241

    
1242
	$data = load_loader_conf($loader_conf_file);
1243
	if ($serial_only === true) {
1244
		$data[] = 'boot_serial="YES"';
1245
		$data[] = 'console="comconsole"';
1246
		$data[] = 'comconsole_speed="' . $serialspeed . '"';
1247
	} elseif ($vga_only === true) {
1248
		$data[] = 'console="vidconsole"';
1249
	} elseif (is_serial_enabled()) {
1250
		$data[] = 'boot_multicons="YES"';
1251
		$data[] = 'boot_serial="YES"';
1252
		$primaryconsole = isset($g['primaryconsole_force']) ?
1253
		    $g['primaryconsole_force'] :
1254
		    $config['system']['primaryconsole'];
1255
		switch ($primaryconsole) {
1256
			case "video":
1257
				$data[] = 'console="vidconsole,comconsole"';
1258
				break;
1259
			case "serial":
1260
			default:
1261
				$data[] = 'console="comconsole,vidconsole"';
1262
		}
1263
		$data[] = 'comconsole_speed="' . $serialspeed . '"';
1264
	}
1265

    
1266
	if ($specific_platform['name'] == 'RCC-VE' ||
1267
	    $specific_platform['name'] == 'RCC' ||
1268
	    $specific_platform['name'] == 'SG-2220') {
1269
		$data[] = 'comconsole_port="0x2F8"';
1270
		$data[] = 'hint.uart.0.flags="0x00"';
1271
		$data[] = 'hint.uart.1.flags="0x10"';
1272
	}
1273
	$data[] = 'autoboot_delay="3"';
1274
	$data[] = 'hw.usb.no_pf="1"';
1275
	if (isset($config['system']['pti_disabled'])) {
1276
		$data[] = 'vm.pmap.pti="0"';
1277
	}
1278

    
1279
	safe_write_file($loader_conf_file, $data);
1280

    
1281
	/* Filter loader.conf.local to avoid duplicate settings. */
1282
	$loader_conf_file = "{$path}/boot/loader.conf.local";
1283
	$data = load_loader_conf($loader_conf_file, true);
1284
	if (empty($data)) {
1285
		@unlink($loader_conf_file);
1286
	} else {
1287
		safe_write_file($loader_conf_file, $data);
1288
	}
1289

    
1290
}
1291

    
1292
function setup_serial_port($when = "save", $path = "") {
1293
	global $config;
1294
	$ttys_file = "{$path}/etc/ttys";
1295

    
1296
	/* Update the loader settings. */
1297
	setup_loader_settings($path, ($when == "upgrade"));
1298

    
1299
	$ttys = file_get_contents($ttys_file);
1300
	$ttys_split = explode("\n", $ttys);
1301

    
1302
	$data = array();
1303

    
1304
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1305

    
1306
	if (isset($config['system']['disableconsolemenu'])) {
1307
		$console_type = 'Pc';
1308
		$serial_type = '3wire';
1309
	} else {
1310
		$console_type = 'al.Pc';
1311
		$serial_type = 'al.3wire';
1312
	}
1313

    
1314
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1315
	$ttyv0_line =
1316
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\txterm\ton\tsecure";
1317
	$ttyu_line =
1318
	    "\"/usr/libexec/getty {$serial_type}\"\tvt100\t{$on_off}\tsecure";
1319

    
1320
	$found = array();
1321

    
1322
	foreach ($ttys_split as $tty) {
1323
		/* Ignore blank lines */
1324
		if (empty($tty)) {
1325
			continue;
1326
		}
1327

    
1328
		if (stristr($tty, "ttyv0")) {
1329
			$found['ttyv0'] = 1;
1330
			$data[] = $ttyv0_line;
1331
		} elseif (stristr($tty, "ttyu")) {
1332
			$ttyn = substr($tty, 0, 5);
1333
			$found[$ttyn] = 1;
1334
			$data[] = "{$ttyn}\t{$ttyu_line}";
1335
		} elseif (substr($tty, 0, 7) == 'console') {
1336
			$found['console'] = 1;
1337
			$data[] = $tty;
1338
		} else {
1339
			$data[] = $tty;
1340
		}
1341
	}
1342
	unset($on_off, $console_type, $serial_type);
1343

    
1344
	/* Detect missing main lines on original file and try to rebuild it */
1345
	$items = array(
1346
		'console',
1347
		'ttyv0',
1348
		'ttyu0',
1349
		'ttyu1',
1350
		'ttyu2',
1351
		'ttyu3'
1352
	);
1353

    
1354
	foreach ($items as $item) {
1355
		if (isset($found[$item])) {
1356
			continue;
1357
		}
1358

    
1359
		if ($item == 'console') {
1360
			$data[] = $console_line;
1361
		} elseif ($item == 'ttyv0') {
1362
			$data[] = $ttyv0_line;
1363
		} else {
1364
			$data[] = "{$item}\t{$ttyu_line}";
1365
		}
1366
	}
1367

    
1368
	safe_write_file($ttys_file, $data);
1369

    
1370
	unset($ttys, $ttys_file, $ttys_split, $data);
1371

    
1372
	if ($when != "upgrade") {
1373
		reload_ttys();
1374
	}
1375

    
1376
	return;
1377
}
1378

    
1379
function is_serial_enabled() {
1380
	global $g, $config;
1381

    
1382
	if (!isset($g['enableserial_force']) &&
1383
	    !isset($config['system']['enableserial'])) {
1384
		return false;
1385
	}
1386

    
1387
	return true;
1388
}
1389

    
1390
function reload_ttys() {
1391
	// Send a HUP signal to init will make it reload /etc/ttys
1392
	posix_kill(1, SIGHUP);
1393
}
1394

    
1395
function print_value_list($list, $count = 10, $separator = ",") {
1396
	$list = implode($separator, array_slice($list, 0, $count));
1397
	if (count($list) < $count) {
1398
		$list .= ".";
1399
	} else {
1400
		$list .= "...";
1401
	}
1402
	return $list;
1403
}
1404

    
1405
/* DHCP enabled on any interfaces? */
1406
function is_dhcp_server_enabled() {
1407
	global $config;
1408

    
1409
	if (!is_array($config['dhcpd'])) {
1410
		return false;
1411
	}
1412

    
1413
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1414
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1415
			return true;
1416
		}
1417
	}
1418

    
1419
	return false;
1420
}
1421

    
1422
/* DHCP enabled on any interfaces? */
1423
function is_dhcpv6_server_enabled() {
1424
	global $config;
1425

    
1426
	if (is_array($config['interfaces'])) {
1427
		foreach ($config['interfaces'] as $ifcfg) {
1428
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1429
				return true;
1430
			}
1431
		}
1432
	}
1433

    
1434
	if (!is_array($config['dhcpdv6'])) {
1435
		return false;
1436
	}
1437

    
1438
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1439
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1440
			return true;
1441
		}
1442
	}
1443

    
1444
	return false;
1445
}
1446

    
1447
/* radvd enabled on any interfaces? */
1448
function is_radvd_enabled() {
1449
	global $config;
1450

    
1451
	if (!is_array($config['dhcpdv6'])) {
1452
		$config['dhcpdv6'] = array();
1453
	}
1454

    
1455
	$dhcpdv6cfg = $config['dhcpdv6'];
1456
	$Iflist = get_configured_interface_list();
1457

    
1458
	/* handle manually configured DHCP6 server settings first */
1459
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1460
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1461
			continue;
1462
		}
1463

    
1464
		if (!isset($dhcpv6ifconf['ramode'])) {
1465
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1466
		}
1467

    
1468
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1469
			continue;
1470
		}
1471

    
1472
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1473
		if (!is_ipaddrv6($ifcfgipv6)) {
1474
			continue;
1475
		}
1476

    
1477
		return true;
1478
	}
1479

    
1480
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1481
	foreach ($Iflist as $if => $ifdescr) {
1482
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1483
			continue;
1484
		}
1485
		if (!isset($config['interfaces'][$if]['enable'])) {
1486
			continue;
1487
		}
1488

    
1489
		$ifcfgipv6 = get_interface_ipv6($if);
1490
		if (!is_ipaddrv6($ifcfgipv6)) {
1491
			continue;
1492
		}
1493

    
1494
		$ifcfgsnv6 = get_interface_subnetv6($if);
1495
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1496

    
1497
		if (!is_ipaddrv6($subnetv6)) {
1498
			continue;
1499
		}
1500

    
1501
		return true;
1502
	}
1503

    
1504
	return false;
1505
}
1506

    
1507
/* Any PPPoE servers enabled? */
1508
function is_pppoe_server_enabled() {
1509
	global $config;
1510

    
1511
	$pppoeenable = false;
1512

    
1513
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1514
		return false;
1515
	}
1516

    
1517
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1518
		if ($pppoes['mode'] == 'server') {
1519
			$pppoeenable = true;
1520
		}
1521
	}
1522

    
1523
	return $pppoeenable;
1524
}
1525

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

    
1540
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1541

    
1542
function get_ppp_uptime($port) {
1543
	if (file_exists("/conf/{$port}.log")) {
1544
		$saved_time = file_get_contents("/conf/{$port}.log");
1545
		$uptime_data = explode("\n", $saved_time);
1546
		$sec = 0;
1547
		foreach ($uptime_data as $upt) {
1548
			$sec += substr($upt, 1 + strpos($upt, " "));
1549
		}
1550
		return convert_seconds_to_dhms($sec);
1551
	} else {
1552
		$total_time = gettext("No history data found!");
1553
		return $total_time;
1554
	}
1555
}
1556

    
1557
//returns interface information
1558
function get_interface_info($ifdescr) {
1559
	global $config, $g;
1560

    
1561
	$ifinfo = array();
1562
	if (empty($config['interfaces'][$ifdescr])) {
1563
		return;
1564
	}
1565
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1566
	$ifinfo['enable'] = isset($config['interfaces'][$ifdescr]['enable']);
1567
	$ifinfo['if'] = get_real_interface($ifdescr);
1568

    
1569
	$chkif = $ifinfo['if'];
1570
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1571
	$ifinfo['status'] = $ifinfotmp['status'];
1572
	if (empty($ifinfo['status'])) {
1573
		$ifinfo['status'] = "down";
1574
	}
1575
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1576
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1577
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1578
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1579
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1580
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1581
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1582
	if (isset($ifinfotmp['link0'])) {
1583
		$link0 = "down";
1584
	}
1585
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1586
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1587
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1588
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1589
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1590
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1591

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

    
1612
	/* Block */
1613
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1614
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1615
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1616
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1617
	$in4_block = $pf_in4_block[5];
1618
	$out4_block = $pf_out4_block[5];
1619
	$in4_block_packets = $pf_in4_block[3];
1620
	$out4_block_packets = $pf_out4_block[3];
1621
	$in6_block = $pf_in6_block[5];
1622
	$out6_block = $pf_out6_block[5];
1623
	$in6_block_packets = $pf_in6_block[3];
1624
	$out6_block_packets = $pf_out6_block[3];
1625
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1626
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1627
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1628
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1629

    
1630
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1631
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1632
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1633
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1634

    
1635
	$ifconfiginfo = "";
1636
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1637
	switch ($link_type) {
1638
		/* DHCP? -> see if dhclient is up */
1639
		case "dhcp":
1640
			/* see if dhclient is up */
1641
			if (find_dhclient_process($ifinfo['if']) != 0) {
1642
				$ifinfo['dhcplink'] = "up";
1643
			} else {
1644
				$ifinfo['dhcplink'] = "down";
1645
			}
1646

    
1647
			break;
1648
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1649
		case "pppoe":
1650
		case "pptp":
1651
		case "l2tp":
1652
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1653
				/* get PPPoE link status for dial on demand */
1654
				$ifinfo["{$link_type}link"] = "up";
1655
			} else {
1656
				$ifinfo["{$link_type}link"] = "down";
1657
			}
1658

    
1659
			break;
1660
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1661
		case "ppp":
1662
			if ($ifinfo['status'] == "up") {
1663
				$ifinfo['ppplink'] = "up";
1664
			} else {
1665
				$ifinfo['ppplink'] = "down" ;
1666
			}
1667

    
1668
			if (empty($ifinfo['status'])) {
1669
				$ifinfo['status'] = "down";
1670
			}
1671

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

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

    
1723
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1724
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1725
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1726
	}
1727

    
1728
	if ($ifinfo['status'] == "up") {
1729
		/* try to determine media with ifconfig */
1730
		unset($ifconfiginfo);
1731
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1732
		$wifconfiginfo = array();
1733
		if (is_interface_wireless($ifdescr)) {
1734
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1735
			array_shift($wifconfiginfo);
1736
		}
1737
		$matches = "";
1738
		foreach ($ifconfiginfo as $ici) {
1739

    
1740
			/* don't list media/speed for wireless cards, as it always
1741
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1742
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1743
				$ifinfo['media'] = $matches[1];
1744
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1745
				$ifinfo['media'] = $matches[1];
1746
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1747
				$ifinfo['media'] = $matches[1];
1748
			}
1749

    
1750
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1751
				if ($matches[1] != "active") {
1752
					$ifinfo['status'] = $matches[1];
1753
				}
1754
				if ($ifinfo['status'] == gettext("running")) {
1755
					$ifinfo['status'] = gettext("up");
1756
				}
1757
			}
1758
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1759
				$ifinfo['channel'] = $matches[1];
1760
			}
1761
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1762
				if ($matches[1][0] == '"') {
1763
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1764
				}
1765
				else {
1766
					$ifinfo['ssid'] = $matches[1];
1767
				}
1768
			}
1769
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1770
				$ifinfo['laggproto'] = $matches[1];
1771
			}
1772
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1773
				$ifinfo['laggport'][] = $matches[1];
1774
			}
1775
		}
1776
		foreach ($wifconfiginfo as $ici) {
1777
			$elements = preg_split("/[ ]+/i", $ici);
1778
			if ($elements[0] != "") {
1779
				$ifinfo['bssid'] = $elements[0];
1780
			}
1781
			if ($elements[3] != "") {
1782
				$ifinfo['rate'] = $elements[3];
1783
			}
1784
			if ($elements[4] != "") {
1785
				$ifinfo['rssi'] = $elements[4];
1786
			}
1787
		}
1788
		/* lookup the gateway */
1789
		if (interface_has_gateway($ifdescr)) {
1790
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1791
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1792
		}
1793
	}
1794

    
1795
	$bridge = "";
1796
	$bridge = link_interface_to_bridge($ifdescr);
1797
	if ($bridge) {
1798
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1799
		if (stristr($bridge_text, "blocking") <> false) {
1800
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1801
			$ifinfo['bridgeint'] = $bridge;
1802
		} else if (stristr($bridge_text, "learning") <> false) {
1803
			$ifinfo['bridge'] = gettext("learning");
1804
			$ifinfo['bridgeint'] = $bridge;
1805
		} else if (stristr($bridge_text, "forwarding") <> false) {
1806
			$ifinfo['bridge'] = gettext("forwarding");
1807
			$ifinfo['bridgeint'] = $bridge;
1808
		}
1809
	}
1810

    
1811
	return $ifinfo;
1812
}
1813

    
1814
//returns cpu speed of processor. Good for determining capabilities of machine
1815
function get_cpu_speed() {
1816
	return get_single_sysctl("hw.clockrate");
1817
}
1818

    
1819
function get_uptime_sec() {
1820
	$boottime = "";
1821
	$matches = "";
1822
	$boottime = get_single_sysctl("kern.boottime");
1823
	preg_match("/sec = (\d+)/", $boottime, $matches);
1824
	$boottime = $matches[1];
1825
	if (intval($boottime) == 0) {
1826
		return 0;
1827
	}
1828

    
1829
	$uptime = time() - $boottime;
1830
	return $uptime;
1831
}
1832

    
1833
function add_hostname_to_watch($hostname) {
1834
	if (!is_dir("/var/db/dnscache")) {
1835
		mkdir("/var/db/dnscache");
1836
	}
1837
	$result = array();
1838
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1839
		$domrecords = array();
1840
		$domips = array();
1841
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1842
		if ($rethost == 0) {
1843
			foreach ($domrecords as $domr) {
1844
				$doml = explode(" ", $domr);
1845
				$domip = $doml[3];
1846
				/* fill array with domain ip addresses */
1847
				if (is_ipaddr($domip)) {
1848
					$domips[] = $domip;
1849
				}
1850
			}
1851
		}
1852
		sort($domips);
1853
		$contents = "";
1854
		if (!empty($domips)) {
1855
			foreach ($domips as $ip) {
1856
				$contents .= "$ip\n";
1857
			}
1858
		}
1859
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1860
		/* Remove empty elements */
1861
		$result = array_filter(explode("\n", $contents), 'strlen');
1862
	}
1863
	return $result;
1864
}
1865

    
1866
function is_fqdn($fqdn) {
1867
	$hostname = false;
1868
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1869
		$hostname = true;
1870
	}
1871
	if (preg_match("/\.\./", $fqdn)) {
1872
		$hostname = false;
1873
	}
1874
	if (preg_match("/^\./i", $fqdn)) {
1875
		$hostname = false;
1876
	}
1877
	if (preg_match("/\//i", $fqdn)) {
1878
		$hostname = false;
1879
	}
1880
	return($hostname);
1881
}
1882

    
1883
function pfsense_default_state_size() {
1884
	/* get system memory amount */
1885
	$memory = get_memory();
1886
	$physmem = $memory[0];
1887
	/* Be cautious and only allocate 10% of system memory to the state table */
1888
	$max_states = (int) ($physmem/10)*1000;
1889
	return $max_states;
1890
}
1891

    
1892
function pfsense_default_tables_size() {
1893
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1894
	return $current;
1895
}
1896

    
1897
function pfsense_default_table_entries_size() {
1898
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1899
	return (trim($current));
1900
}
1901

    
1902
/* Compare the current hostname DNS to the DNS cache we made
1903
 * if it has changed we return the old records
1904
 * if no change we return false */
1905
function compare_hostname_to_dnscache($hostname) {
1906
	if (!is_dir("/var/db/dnscache")) {
1907
		mkdir("/var/db/dnscache");
1908
	}
1909
	$hostname = trim($hostname);
1910
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1911
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1912
	} else {
1913
		$oldcontents = "";
1914
	}
1915
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1916
		$domrecords = array();
1917
		$domips = array();
1918
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1919
		if ($rethost == 0) {
1920
			foreach ($domrecords as $domr) {
1921
				$doml = explode(" ", $domr);
1922
				$domip = $doml[3];
1923
				/* fill array with domain ip addresses */
1924
				if (is_ipaddr($domip)) {
1925
					$domips[] = $domip;
1926
				}
1927
			}
1928
		}
1929
		sort($domips);
1930
		$contents = "";
1931
		if (!empty($domips)) {
1932
			foreach ($domips as $ip) {
1933
				$contents .= "$ip\n";
1934
			}
1935
		}
1936
	}
1937

    
1938
	if (trim($oldcontents) != trim($contents)) {
1939
		if ($g['debug']) {
1940
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1941
		}
1942
		return ($oldcontents);
1943
	} else {
1944
		return false;
1945
	}
1946
}
1947

    
1948
/*
1949
 * load_crypto() - Load crypto modules if enabled in config.
1950
 */
1951
function load_crypto() {
1952
	global $config, $g;
1953
	$crypto_modules = array('aesni', 'cryptodev');
1954

    
1955
	$enabled_modules = explode('_', $config['system']['crypto_hardware']);
1956

    
1957
	foreach ($enabled_modules as $enmod) {
1958
		if (empty($enmod) || !in_array($enmod, $crypto_modules)) {
1959
			continue;
1960
		}
1961
		if (!is_module_loaded($enmod)) {
1962
			log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $enmod));
1963
			mwexec("/sbin/kldload " . escapeshellarg($enmod));
1964
		}
1965
	}
1966
}
1967

    
1968
/*
1969
 * load_thermal_hardware() - Load temperature monitor kernel module
1970
 */
1971
function load_thermal_hardware() {
1972
	global $config, $g;
1973
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1974

    
1975
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1976
		return false;
1977
	}
1978

    
1979
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1980
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1981
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1982
	}
1983
}
1984

    
1985
/****f* pfsense-utils/isvm
1986
 * NAME
1987
 *   isvm
1988
 * INPUTS
1989
 *	none
1990
 * RESULT
1991
 *   returns true if machine is running under a virtual environment
1992
 ******/
1993
function isvm() {
1994
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
1995
	$_gb = exec('/bin/kenv -q smbios.system.product 2>/dev/null', $output, $rc);
1996

    
1997
	if ($rc != 0 || !isset($output[0])) {
1998
		return false;
1999
	}
2000

    
2001
	foreach ($virtualenvs as $virtualenv) {
2002
		if (stripos($output[0], $virtualenv) !== false) {
2003
			return true;
2004
		}
2005
	}
2006

    
2007
	return false;
2008
}
2009

    
2010
function get_freebsd_version() {
2011
	$version = explode(".", php_uname("r"));
2012
	return $version[0];
2013
}
2014

    
2015
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
2016
	global $config, $g;
2017

    
2018
	$fp = fopen($destination, "wb");
2019

    
2020
	if (!$fp) {
2021
		return false;
2022
	}
2023

    
2024
	$ch = curl_init();
2025
	curl_setopt($ch, CURLOPT_URL, $url);
2026
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
2027
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2028
	curl_setopt($ch, CURLOPT_FILE, $fp);
2029
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2030
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2031
	curl_setopt($ch, CURLOPT_HEADER, false);
2032
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2033
	if (!isset($config['system']['do_not_send_uniqueid'])) {
2034
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
2035
	} else {
2036
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2037
	}
2038

    
2039
	if (!empty($config['system']['proxyurl'])) {
2040
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2041
		if (!empty($config['system']['proxyport'])) {
2042
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2043
		}
2044
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2045
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2046
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2047
		}
2048
	}
2049

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

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

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

    
2095
	if (!empty($config['system']['proxyurl'])) {
2096
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2097
		if (!empty($config['system']['proxyport'])) {
2098
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2099
		}
2100
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2101
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2102
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2103
		}
2104
	}
2105

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

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

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

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

    
2203
/*
2204
 *   update_status: update top textarea dynamically.
2205
 */
2206
function update_status($status) {
2207
	global $pkg_interface;
2208

    
2209
	if ($pkg_interface == "console") {
2210
		print ("{$status}");
2211
	}
2212

    
2213
	/* ensure that contents are written out */
2214
	ob_flush();
2215
}
2216

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

    
2239
function update_alias_name($new_alias_name, $orig_alias_name) {
2240
	if (!$orig_alias_name) {
2241
		return;
2242
	}
2243

    
2244
	// Firewall rules
2245
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2246
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2247
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2248
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2249
	// NAT Rules
2250
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2251
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2252
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2253
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2254
	update_alias_names_upon_change(array('nat', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2255
	update_alias_names_upon_change(array('nat', 'rule'), array('local-port'), $new_alias_name, $orig_alias_name);
2256
	// NAT 1:1 Rules
2257
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('external'), $new_alias_name, $orig_alias_name);
2258
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2259
	update_alias_names_upon_change(array('nat', 'onetoone'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2260
	// NAT Outbound Rules
2261
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('source', 'network'), $new_alias_name, $orig_alias_name);
2262
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('sourceport'), $new_alias_name, $orig_alias_name);
2263
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2264
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('dstport'), $new_alias_name, $orig_alias_name);
2265
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2266
	// Alias in an alias
2267
	update_alias_names_upon_change(array('aliases', 'alias'), array('address'), $new_alias_name, $orig_alias_name);
2268
}
2269

    
2270
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2271
	global $g, $config, $pconfig, $debug;
2272
	if (!$origname) {
2273
		return;
2274
	}
2275

    
2276
	$sectionref = &$config;
2277
	foreach ($section as $sectionname) {
2278
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2279
			$sectionref = &$sectionref[$sectionname];
2280
		} else {
2281
			return;
2282
		}
2283
	}
2284

    
2285
	if ($debug) {
2286
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2287
		fwrite($fd, print_r($pconfig, true));
2288
	}
2289

    
2290
	if (is_array($sectionref)) {
2291
		foreach ($sectionref as $itemkey => $item) {
2292
			if ($debug) {
2293
				fwrite($fd, "$itemkey\n");
2294
			}
2295

    
2296
			$fieldfound = true;
2297
			$fieldref = &$sectionref[$itemkey];
2298
			foreach ($field as $fieldname) {
2299
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2300
					$fieldref = &$fieldref[$fieldname];
2301
				} else {
2302
					$fieldfound = false;
2303
					break;
2304
				}
2305
			}
2306
			if ($fieldfound && $fieldref == $origname) {
2307
				if ($debug) {
2308
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2309
				}
2310
				$fieldref = $new_alias_name;
2311
			}
2312
		}
2313
	}
2314

    
2315
	if ($debug) {
2316
		fclose($fd);
2317
	}
2318

    
2319
}
2320

    
2321
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2322
	/*
2323
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2324
	 * $type = if set to 'url' then subnets and ips will be returned,
2325
	 *         if set to 'url_ports' port-ranges and ports will be returned
2326
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2327
	 *
2328
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2329
	 */
2330

    
2331
	if (!file_exists($filename)) {
2332
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2333
		return null;
2334
	}
2335

    
2336
	if (filesize($filename) == 0) {
2337
		log_error(sprintf(gettext("Could not process empty file from alias: %s"), $filename));
2338
		return null;
2339
	}
2340
	$fd = @fopen($filename, 'r');
2341
	if (!$fd) {
2342
		log_error(sprintf(gettext("Could not process aliases from alias: %s"), $filename));
2343
		return null;
2344
	}
2345
	$items = array();
2346
	$comments = array();
2347
	/* NOTE: fgetss() is not a typo RTFM before being smart */
2348
	while (($fc = fgetss($fd)) !== FALSE) {
2349
		$tmp = trim($fc, " \t\n\r");
2350
		if (empty($tmp)) {
2351
			continue;
2352
		}
2353
		if (($kflc) && (strpos($tmp, '#') === 0)) {	// Keep Full Line Comments (lines beginning with #).
2354
			$comments[] = $tmp;
2355
		} else {
2356
			$tmp_str = strstr($tmp, '#', true);
2357
			if (!empty($tmp_str)) {
2358
				$tmp = $tmp_str;
2359
			}
2360
			$tmp_str = strstr($tmp, ' ', true);
2361
			if (!empty($tmp_str)) {
2362
				$tmp = $tmp_str;
2363
			}
2364
			$valid = (($type == "url" || $type == "urltable") && (is_ipaddr($tmp) || is_subnet($tmp))) ||
2365
				(($type == "url_ports" || $type == "urltable_ports") && is_port_or_range($tmp));
2366
			if ($valid) {
2367
				$items[] = $tmp;
2368
				if (count($items) == $max_items) {
2369
					break;
2370
				}
2371
			}
2372
		}
2373
	}
2374
	fclose($fd);
2375
	return array_merge($comments, $items);
2376
}
2377

    
2378
function update_alias_url_data() {
2379
	global $config, $g;
2380

    
2381
	$updated = false;
2382

    
2383
	/* item is a url type */
2384
	$lockkey = lock('aliasurl');
2385
	if (is_array($config['aliases']['alias'])) {
2386
		foreach ($config['aliases']['alias'] as $x => $alias) {
2387
			if (empty($alias['aliasurl'])) {
2388
				continue;
2389
			}
2390

    
2391
			$address = null;
2392
			foreach ($alias['aliasurl'] as $alias_url) {
2393
				/* fetch down and add in */
2394
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2395
				unlink($temp_filename);
2396
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2397
				mkdir($temp_filename);
2398
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2399
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2400
					continue;
2401
				}
2402

    
2403
				/* if the item is tar gzipped then extract */
2404
				if (stripos($alias_url, '.tgz')) {
2405
					if (!process_alias_tgz($temp_filename)) {
2406
						continue;
2407
					}
2408
				}
2409
				if (file_exists("{$temp_filename}/aliases")) {
2410
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2411
					mwexec("/bin/rm -rf {$temp_filename}");
2412
				}
2413
			}
2414
			if ($address != null) {
2415
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2416
				$updated = true;
2417
			}
2418
		}
2419
	}
2420
	unlock($lockkey);
2421

    
2422
	/* Report status to callers as well */
2423
	return $updated;
2424
}
2425

    
2426
function process_alias_tgz($temp_filename) {
2427
	if (!file_exists('/usr/bin/tar')) {
2428
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2429
		return false;
2430
	}
2431
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2432
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2433
	unlink("{$temp_filename}/aliases.tgz");
2434
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2435
	/* foreach through all extracted files and build up aliases file */
2436
	$fd = @fopen("{$temp_filename}/aliases", "w");
2437
	if (!$fd) {
2438
		log_error(sprintf(gettext("Could not open %s/aliases for writing!"), $temp_filename));
2439
		return false;
2440
	}
2441
	foreach ($files_to_process as $f2p) {
2442
		$tmpfd = @fopen($f2p, 'r');
2443
		if (!$tmpfd) {
2444
			log_error(sprintf(gettext('The following file could not be read %1$s from %2$s'), $f2p, $temp_filename));
2445
			continue;
2446
		}
2447
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2448
			fwrite($fd, $tmpbuf);
2449
		}
2450
		fclose($tmpfd);
2451
		unlink($f2p);
2452
	}
2453
	fclose($fd);
2454
	unset($tmpbuf);
2455

    
2456
	return true;
2457
}
2458

    
2459
function version_compare_dates($a, $b) {
2460
	$a_time = strtotime($a);
2461
	$b_time = strtotime($b);
2462

    
2463
	if ((!$a_time) || (!$b_time)) {
2464
		return FALSE;
2465
	} else {
2466
		if ($a_time < $b_time) {
2467
			return -1;
2468
		} elseif ($a_time == $b_time) {
2469
			return 0;
2470
		} else {
2471
			return 1;
2472
		}
2473
	}
2474
}
2475
function version_get_string_value($a) {
2476
	$strs = array(
2477
		0 => "ALPHA-ALPHA",
2478
		2 => "ALPHA",
2479
		3 => "BETA",
2480
		4 => "B",
2481
		5 => "C",
2482
		6 => "D",
2483
		7 => "RC",
2484
		8 => "RELEASE",
2485
		9 => "*"			// Matches all release levels
2486
	);
2487
	$major = 0;
2488
	$minor = 0;
2489
	foreach ($strs as $num => $str) {
2490
		if (substr($a, 0, strlen($str)) == $str) {
2491
			$major = $num;
2492
			$n = substr($a, strlen($str));
2493
			if (is_numeric($n)) {
2494
				$minor = $n;
2495
			}
2496
			break;
2497
		}
2498
	}
2499
	return "{$major}.{$minor}";
2500
}
2501
function version_compare_string($a, $b) {
2502
	// Only compare string parts if both versions give a specific release
2503
	// (If either version lacks a string part, assume intended to match all release levels)
2504
	if (isset($a) && isset($b)) {
2505
		return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
2506
	} else {
2507
		return 0;
2508
	}
2509
}
2510
function version_compare_numeric($a, $b) {
2511
	$a_arr = explode('.', rtrim($a, '.'));
2512
	$b_arr = explode('.', rtrim($b, '.'));
2513

    
2514
	foreach ($a_arr as $n => $val) {
2515
		if (array_key_exists($n, $b_arr)) {
2516
			// So far so good, both have values at this minor version level. Compare.
2517
			if ($val > $b_arr[$n]) {
2518
				return 1;
2519
			} elseif ($val < $b_arr[$n]) {
2520
				return -1;
2521
			}
2522
		} else {
2523
			// a is greater, since b doesn't have any minor version here.
2524
			return 1;
2525
		}
2526
	}
2527
	if (count($b_arr) > count($a_arr)) {
2528
		// b is longer than a, so it must be greater.
2529
		return -1;
2530
	} else {
2531
		// Both a and b are of equal length and value.
2532
		return 0;
2533
	}
2534
}
2535
function pfs_version_compare($cur_time, $cur_text, $remote) {
2536
	// First try date compare
2537
	$v = version_compare_dates($cur_time, $remote);
2538
	if ($v === FALSE) {
2539
		// If that fails, try to compare by string
2540
		// Before anything else, simply test if the strings are equal
2541
		if (($cur_text == $remote) || ($cur_time == $remote)) {
2542
			return 0;
2543
		}
2544
		list($cur_num, $cur_str) = explode('-', $cur_text);
2545
		list($rem_num, $rem_str) = explode('-', $remote);
2546

    
2547
		// First try to compare the numeric parts of the version string.
2548
		$v = version_compare_numeric($cur_num, $rem_num);
2549

    
2550
		// If the numeric parts are the same, compare the string parts.
2551
		if ($v == 0) {
2552
			return version_compare_string($cur_str, $rem_str);
2553
		}
2554
	}
2555
	return $v;
2556
}
2557
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2558
	global $g, $config;
2559

    
2560
	$urltable_prefix = "/var/db/aliastables/";
2561
	$urltable_filename = $urltable_prefix . $name . ".txt";
2562
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2563

    
2564
	// Make the aliases directory if it doesn't exist
2565
	if (!file_exists($urltable_prefix)) {
2566
		mkdir($urltable_prefix);
2567
	} elseif (!is_dir($urltable_prefix)) {
2568
		unlink($urltable_prefix);
2569
		mkdir($urltable_prefix);
2570
	}
2571

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

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

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

    
2586
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2587
			if ($type == "urltable_ports") {
2588
				$parsed_contents = group_ports($parsed_contents, true);
2589
			}
2590
			if (is_array($parsed_contents)) {
2591
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2592
			} else {
2593
				touch($urltable_filename);
2594
			}
2595

    
2596
			/* Remove existing archive and create an up to date archive if RAM disk is enabled. */
2597
			unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz");
2598
			if (isset($config['system']['use_mfs_tmpvar'])) {
2599
				mwexec("/usr/bin/tar -czf " . escapeshellarg("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz") . " -C / " . escapeshellarg($urltable_filename));
2600
			}
2601

    
2602
			unlink_if_exists($tmp_urltable_filename);
2603
		} else {
2604
			if (!$validateonly) {
2605
				touch($urltable_filename);
2606
			}
2607
			return false;
2608
		}
2609
		return true;
2610
	} else {
2611
		// File exists, and it doesn't need to be updated.
2612
		return -1;
2613
	}
2614
}
2615

    
2616
function get_include_contents($filename) {
2617
	if (is_file($filename)) {
2618
		ob_start();
2619
		include $filename;
2620
		$contents = ob_get_contents();
2621
		ob_end_clean();
2622
		return $contents;
2623
	}
2624
	return false;
2625
}
2626

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

    
2739
function get_country_name($country_code) {
2740
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2741
		return "";
2742
	}
2743

    
2744
	$country_names_xml = "/usr/local/share/pfSense/iso_3166-1_list_en.xml";
2745
	$country_names_contents = file_get_contents($country_names_xml);
2746
	$country_names = xml2array($country_names_contents);
2747

    
2748
	if ($country_code == "ALL") {
2749
		$country_list = array();
2750
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2751
			$country_list[] = array(
2752
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2753
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2754
		}
2755
		return $country_list;
2756
	}
2757

    
2758
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2759
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2760
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2761
		}
2762
	}
2763
	return "";
2764
}
2765

    
2766
/* sort by interface only, retain the original order of rules that apply to
2767
   the same interface */
2768
function filter_rules_sort() {
2769
	global $config;
2770

    
2771
	/* mark each rule with the sequence number (to retain the order while sorting) */
2772
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2773
		if (!is_array($config['filter']['rule'][$i])) {
2774
			$config['filter']['rule'][$i] = array();
2775
		}
2776
		$config['filter']['rule'][$i]['seq'] = $i;
2777
	}
2778

    
2779
	usort($config['filter']['rule'], "filter_rules_compare");
2780

    
2781
	/* strip the sequence numbers again */
2782
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2783
		unset($config['filter']['rule'][$i]['seq']);
2784
	}
2785
}
2786
function filter_rules_compare($a, $b) {
2787
	if (isset($a['floating']) && isset($b['floating'])) {
2788
		return $a['seq'] - $b['seq'];
2789
	} else if (isset($a['floating'])) {
2790
		return -1;
2791
	} else if (isset($b['floating'])) {
2792
		return 1;
2793
	} else if ($a['interface'] == $b['interface']) {
2794
		return $a['seq'] - $b['seq'];
2795
	} else {
2796
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2797
	}
2798
}
2799

    
2800
function generate_ipv6_from_mac($mac) {
2801
	$elements = explode(":", $mac);
2802
	if (count($elements) <> 6) {
2803
		return false;
2804
	}
2805

    
2806
	$i = 0;
2807
	$ipv6 = "fe80::";
2808
	foreach ($elements as $byte) {
2809
		if ($i == 0) {
2810
			$hexadecimal = substr($byte, 1, 2);
2811
			$bitmap = base_convert($hexadecimal, 16, 2);
2812
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2813
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2814
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2815
		}
2816
		$ipv6 .= $byte;
2817
		if ($i == 1) {
2818
			$ipv6 .= ":";
2819
		}
2820
		if ($i == 3) {
2821
			$ipv6 .= ":";
2822
		}
2823
		if ($i == 2) {
2824
			$ipv6 .= "ff:fe";
2825
		}
2826

    
2827
		$i++;
2828
	}
2829
	return $ipv6;
2830
}
2831

    
2832
/****f* pfsense-utils/load_mac_manufacturer_table
2833
 * NAME
2834
 *   load_mac_manufacturer_table
2835
 * INPUTS
2836
 *   none
2837
 * RESULT
2838
 *   returns associative array with MAC-Manufacturer pairs
2839
 ******/
2840
function load_mac_manufacturer_table() {
2841
	/* load MAC-Manufacture data from the file */
2842
	$macs = false;
2843
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2844
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2845
	}
2846
	if ($macs) {
2847
		foreach ($macs as $line) {
2848
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2849
				/* store values like this $mac_man['000C29']='VMware' */
2850
				$mac_man["$matches[1]"] = $matches[2];
2851
			}
2852
		}
2853
		return $mac_man;
2854
	} else {
2855
		return -1;
2856
	}
2857

    
2858
}
2859

    
2860
/****f* pfsense-utils/is_ipaddr_configured
2861
 * NAME
2862
 *   is_ipaddr_configured
2863
 * INPUTS
2864
 *   IP Address to check.
2865
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2866
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2867
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2868
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2869
 *     If check_subnets is true and cidrprefix is specified,
2870
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2871
 * RESULT
2872
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2873
*/
2874
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2875
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2876
		return true;
2877
	}
2878
	return false;
2879
}
2880

    
2881
/****f* pfsense-utils/where_is_ipaddr_configured
2882
 * NAME
2883
 *   where_is_ipaddr_configured
2884
 * INPUTS
2885
 *   IP Address to check.
2886
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2887
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2888
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2889
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2890
 *     If check_subnets is true and cidrprefix is specified,
2891
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2892
 * RESULT
2893
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2894
 *   If there are no matches then an empty array is returned.
2895
*/
2896
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2897
	global $config;
2898

    
2899
	$where_configured = array();
2900

    
2901
	$pos = strpos($ignore_if, '_virtualip');
2902
	if ($pos !== false) {
2903
		$ignore_vip_id = substr($ignore_if, $pos+10);
2904
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2905
	} else {
2906
		$ignore_vip_id = -1;
2907
		$ignore_vip_if = $ignore_if;
2908
	}
2909

    
2910
	$isipv6 = is_ipaddrv6($ipaddr);
2911

    
2912
	if ($isipv6) {
2913
		$ipaddr = text_to_compressed_ip6($ipaddr);
2914
	}
2915

    
2916
	if ($check_subnets) {
2917
		$cidrprefix = intval($cidrprefix);
2918
		if ($isipv6) {
2919
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2920
				$cidrprefix = 128;
2921
			}
2922
		} else {
2923
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2924
				$cidrprefix = 32;
2925
			}
2926
		}
2927
		$iflist = get_configured_interface_list();
2928
		foreach ($iflist as $if => $ifname) {
2929
			if ($ignore_if == $if) {
2930
				continue;
2931
			}
2932

    
2933
			if ($isipv6) {
2934
				$if_ipv6 = get_interface_ipv6($if);
2935
				$if_snbitsv6 = get_interface_subnetv6($if);
2936
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2937
					$where_entry = array();
2938
					$where_entry['if'] = $if;
2939
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2940
					$where_configured[] = $where_entry;
2941
				}
2942
			} else {
2943
				$if_ipv4 = get_interface_ip($if);
2944
				$if_snbitsv4 = get_interface_subnet($if);
2945
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
2946
					$where_entry = array();
2947
					$where_entry['if'] = $if;
2948
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
2949
					$where_configured[] = $where_entry;
2950
				}
2951
			}
2952
		}
2953
	} else {
2954
		if ($isipv6) {
2955
			$interface_list_ips = get_configured_ipv6_addresses();
2956
		} else {
2957
			$interface_list_ips = get_configured_ip_addresses();
2958
		}
2959

    
2960
		foreach ($interface_list_ips as $if => $ilips) {
2961
			if ($ignore_if == $if) {
2962
				continue;
2963
			}
2964
			if (strcasecmp($ipaddr, $ilips) == 0) {
2965
				$where_entry = array();
2966
				$where_entry['if'] = $if;
2967
				$where_entry['ip_or_subnet'] = $ilips;
2968
				$where_configured[] = $where_entry;
2969
			}
2970
		}
2971
	}
2972

    
2973
	if ($check_localip) {
2974
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, text_to_compressed_ip6($config['l2tp']['localip'])) == 0)) {
2975
			$where_entry = array();
2976
			$where_entry['if'] = 'l2tp';
2977
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
2978
			$where_configured[] = $where_entry;
2979
		}
2980
	}
2981

    
2982
	return $where_configured;
2983
}
2984

    
2985
/****f* pfsense-utils/pfSense_handle_custom_code
2986
 * NAME
2987
 *   pfSense_handle_custom_code
2988
 * INPUTS
2989
 *   directory name to process
2990
 * RESULT
2991
 *   globs the directory and includes the files
2992
 */
2993
function pfSense_handle_custom_code($src_dir) {
2994
	// Allow extending of the nat edit page and include custom input validation
2995
	if (is_dir("$src_dir")) {
2996
		$cf = glob($src_dir . "/*.inc");
2997
		foreach ($cf as $nf) {
2998
			if ($nf == "." || $nf == "..") {
2999
				continue;
3000
			}
3001
			// Include the extra handler
3002
			include_once("$nf");
3003
		}
3004
	}
3005
}
3006

    
3007
function set_language() {
3008
	global $config, $g;
3009

    
3010
	if (!empty($config['system']['language'])) {
3011
		$lang = $config['system']['language'];
3012
	} elseif (!empty($g['language'])) {
3013
		$lang = $g['language'];
3014
	}
3015
	$lang .= ".UTF-8";
3016

    
3017
	putenv("LANG={$lang}");
3018
	setlocale(LC_ALL, $lang);
3019
	textdomain("pfSense");
3020
	bindtextdomain("pfSense", "/usr/local/share/locale");
3021
	bind_textdomain_codeset("pfSense", $lang);
3022
}
3023

    
3024
function get_locale_list() {
3025
	$locales = array(
3026
		"bs" => gettext("Bosnian"),
3027
		"zh_CN" => gettext("Chinese"),
3028
		"zh_Hans_CN" => gettext("Chinese (Simplified, China)"),
3029
		"zh_HK" => gettext("Chinese (Hong Kong)"),
3030
		"zh_TW" => gettext("Chinese (Taiwan)"),
3031
		"nl" => gettext("Dutch"),
3032
		"en_US" => gettext("English"),
3033
		"fr" => gettext("French"),
3034
		"de_DE" => gettext("German (Germany)"),
3035
		"nb" => gettext("Norwegian Bokmål"),
3036
		"pl" => gettext("Polish"),
3037
		"pt_PT" => gettext("Portuguese"),
3038
		"pt_BR" => gettext("Portuguese (Brazil)"),
3039
		"ru" => gettext("Russian"),
3040
		"es" => gettext("Spanish"),
3041
		"es_AR" => gettext("Spanish (Argentina)"),
3042
	);
3043

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

    
3048
	//asort($locales);
3049

    
3050
	return $locales;
3051
}
3052

    
3053
function return_hex_ipv4($ipv4) {
3054
	if (!is_ipaddrv4($ipv4)) {
3055
		return(false);
3056
	}
3057

    
3058
	/* we need the hex form of the interface IPv4 address */
3059
	$ip4arr = explode(".", $ipv4);
3060
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
3061
}
3062

    
3063
function convert_ipv6_to_128bit($ipv6) {
3064
	if (!is_ipaddrv6($ipv6)) {
3065
		return(false);
3066
	}
3067

    
3068
	$ip6arr = array();
3069
	$ip6prefix = Net_IPv6::uncompress($ipv6);
3070
	$ip6arr = explode(":", $ip6prefix);
3071
	/* binary presentation of the prefix for all 128 bits. */
3072
	$ip6prefixbin = "";
3073
	foreach ($ip6arr as $element) {
3074
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3075
	}
3076
	return($ip6prefixbin);
3077
}
3078

    
3079
function convert_128bit_to_ipv6($ip6bin) {
3080
	if (strlen($ip6bin) <> 128) {
3081
		return(false);
3082
	}
3083

    
3084
	$ip6arr = array();
3085
	$ip6binarr = array();
3086
	$ip6binarr = str_split($ip6bin, 16);
3087
	foreach ($ip6binarr as $binpart) {
3088
		$ip6arr[] = dechex(bindec($binpart));
3089
	}
3090
	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
3091

    
3092
	return($ip6addr);
3093
}
3094

    
3095

    
3096
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3097
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3098
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3099
/* 6to4 is 16 bits, e.g. 65535 */
3100
function calculate_ipv6_delegation_length($if) {
3101
	global $config;
3102

    
3103
	if (!is_array($config['interfaces'][$if])) {
3104
		return false;
3105
	}
3106

    
3107
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3108
		case "6to4":
3109
			$pdlen = 16;
3110
			break;
3111
		case "6rd":
3112
			$rd6cfg = $config['interfaces'][$if];
3113
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3114
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
3115
			break;
3116
		case "dhcp6":
3117
			$dhcp6cfg = $config['interfaces'][$if];
3118
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3119
			break;
3120
		default:
3121
			$pdlen = 0;
3122
			break;
3123
	}
3124
	return($pdlen);
3125
}
3126

    
3127
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3128
	$prefix = Net_IPv6::uncompress($prefix, true);
3129
	$suffix = Net_IPv6::uncompress($suffix, true);
3130

    
3131
	/*
3132
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3133
	 *                ^^^^ ^
3134
	 *                |||| \-> 64
3135
	 *                |||\---> 63, 62, 61, 60
3136
	 *                ||\----> 56
3137
	 *                |\-----> 52
3138
	 *                \------> 48
3139
	 */
3140

    
3141
	switch ($len) {
3142
	case 48:
3143
		$prefix_len = 15;
3144
		break;
3145
	case 52:
3146
		$prefix_len = 16;
3147
		break;
3148
	case 56:
3149
		$prefix_len = 17;
3150
		break;
3151
	case 59:
3152
	case 60:
3153
		$prefix_len = 18;
3154
		break;
3155
	/*
3156
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
3157
	 * we let user chose this bit it can end up out of PD network
3158
	 *
3159
	 * Leave this with 20 for now until we find a way to let user
3160
	 * chose it. The side-effect is users with PD with one of these
3161
	 * lengths will not be able to setup DHCP server range for full
3162
	 * PD size, only for last /64 network
3163
	 */
3164
	case 63:
3165
	case 62:
3166
	case 61:
3167
	default:
3168
		$prefix_len = 20;
3169
		break;
3170
	}
3171

    
3172
	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
3173
	    substr($suffix, $prefix_len));
3174
}
3175

    
3176
function dhcpv6_pd_str_help($pdlen) {
3177
	$result = '';
3178

    
3179
	switch ($pdlen) {
3180
	case 48:
3181
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
3182
		break;
3183
	case 52:
3184
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
3185
		break;
3186
	case 56:
3187
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
3188
		break;
3189
	case 59:
3190
	case 60:
3191
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
3192
		break;
3193
	/*
3194
	 * XXX 63, 62 and 61 should use same mask as 60 but if
3195
	 * we let the user choose this bit it can end up out of PD network
3196
	 *
3197
	 * Leave this with the same as 64 for now until we find a way to
3198
	 * let the user choose it. The side-effect is users with PD with one
3199
	 * of these lengths will not be able to setup DHCP server ranges
3200
	 * for full PD size, only for last /64 network
3201
	 */
3202
	case 61:
3203
	case 62:
3204
	case 63:
3205
	case 64:
3206
	default:
3207
		$result = '::xxxx:xxxx:xxxx:xxxx';
3208
		break;
3209
	}
3210

    
3211
	return $result;
3212
}
3213

    
3214
function huawei_rssi_to_string($rssi) {
3215
	$dbm = array();
3216
	$i = 0;
3217
	$dbstart = -113;
3218
	while ($i < 32) {
3219
		$dbm[$i] = $dbstart + ($i * 2);
3220
		$i++;
3221
	}
3222
	$percent = round(($rssi / 31) * 100);
3223
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3224
	return $string;
3225
}
3226

    
3227
function huawei_mode_to_string($mode, $submode) {
3228
	$modes[0] = gettext("None");
3229
	$modes[1] = "AMPS";
3230
	$modes[2] = "CDMA";
3231
	$modes[3] = "GSM/GPRS";
3232
	$modes[4] = "HDR";
3233
	$modes[5] = "WCDMA";
3234
	$modes[6] = "GPS";
3235

    
3236
	$submodes[0] = gettext("No Service");
3237
	$submodes[1] = "GSM";
3238
	$submodes[2] = "GPRS";
3239
	$submodes[3] = "EDGE";
3240
	$submodes[4] = "WCDMA";
3241
	$submodes[5] = "HSDPA";
3242
	$submodes[6] = "HSUPA";
3243
	$submodes[7] = "HSDPA+HSUPA";
3244
	$submodes[8] = "TD-SCDMA";
3245
	$submodes[9] = "HSPA+";
3246
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3247
	return $string;
3248
}
3249

    
3250
function huawei_service_to_string($state) {
3251
	$modes[0] = gettext("No Service");
3252
	$modes[1] = gettext("Restricted Service");
3253
	$modes[2] = gettext("Valid Service");
3254
	$modes[3] = gettext("Restricted Regional Service");
3255
	$modes[4] = gettext("Powersaving Service");
3256
	$modes[255] = gettext("Unknown Service");
3257
	$string = $modes[$state];
3258
	return $string;
3259
}
3260

    
3261
function huawei_simstate_to_string($state) {
3262
	$modes[0] = gettext("Invalid SIM/locked State");
3263
	$modes[1] = gettext("Valid SIM State");
3264
	$modes[2] = gettext("Invalid SIM CS State");
3265
	$modes[3] = gettext("Invalid SIM PS State");
3266
	$modes[4] = gettext("Invalid SIM CS/PS State");
3267
	$modes[255] = gettext("Missing SIM State");
3268
	$string = $modes[$state];
3269
	return $string;
3270
}
3271

    
3272
function zte_rssi_to_string($rssi) {
3273
	return huawei_rssi_to_string($rssi);
3274
}
3275

    
3276
function zte_mode_to_string($mode, $submode) {
3277
	$modes[0] = gettext("No Service");
3278
	$modes[1] = gettext("Limited Service");
3279
	$modes[2] = "GPRS";
3280
	$modes[3] = "GSM";
3281
	$modes[4] = "UMTS";
3282
	$modes[5] = "EDGE";
3283
	$modes[6] = "HSDPA";
3284

    
3285
	$submodes[0] = "CS_ONLY";
3286
	$submodes[1] = "PS_ONLY";
3287
	$submodes[2] = "CS_PS";
3288
	$submodes[3] = "CAMPED";
3289
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3290
	return $string;
3291
}
3292

    
3293
function zte_service_to_string($service) {
3294
	$modes[0] = gettext("Initializing Service");
3295
	$modes[1] = gettext("Network Lock error Service");
3296
	$modes[2] = gettext("Network Locked Service");
3297
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3298
	$string = $modes[$service];
3299
	return $string;
3300
}
3301

    
3302
function zte_simstate_to_string($state) {
3303
	$modes[0] = gettext("No action State");
3304
	$modes[1] = gettext("Network lock State");
3305
	$modes[2] = gettext("(U)SIM card lock State");
3306
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3307
	$string = $modes[$state];
3308
	return $string;
3309
}
3310

    
3311
function get_configured_pppoe_server_interfaces() {
3312
	global $config;
3313
	$iflist = array();
3314
	if (is_array($config['pppoes']['pppoe'])) {
3315
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3316
			if ($pppoe['mode'] == "server") {
3317
				$int = "poes". $pppoe['pppoeid'];
3318
				$iflist[$int] = strtoupper($int);
3319
			}
3320
		}
3321
	}
3322
	return $iflist;
3323
}
3324

    
3325
function get_pppoes_child_interfaces($ifpattern) {
3326
	$if_arr = array();
3327
	if ($ifpattern == "") {
3328
		return;
3329
	}
3330

    
3331
	exec("/sbin/ifconfig", $out, $ret);
3332
	foreach ($out as $line) {
3333
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3334
			$if_arr[] = $match[1];
3335
		}
3336
	}
3337
	return $if_arr;
3338

    
3339
}
3340

    
3341
/****f* pfsense-utils/pkg_call_plugins
3342
 * NAME
3343
 *   pkg_call_plugins
3344
 * INPUTS
3345
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3346
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3347
 * RESULT
3348
 *   returns associative array results from the plugin calls for each package
3349
 * NOTES
3350
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3351
 ******/
3352
function pkg_call_plugins($plugin_type, $plugin_params) {
3353
	global $g, $config;
3354
	$results = array();
3355
	if (!is_array($config['installedpackages']['package'])) {
3356
		return $results;
3357
	}
3358
	foreach ($config['installedpackages']['package'] as $package) {
3359
		if (is_array($package['plugins']['item'])) {
3360
			foreach ($package['plugins']['item'] as $plugin) {
3361
				if ($plugin['type'] == $plugin_type) {
3362
					if (file_exists($package['include_file'])) {
3363
						require_once($package['include_file']);
3364
					} else {
3365
						continue;
3366
					}
3367
					$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3368
					$plugin_function = $pkgname . '_'. $plugin_type;
3369
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3370
				}
3371
			}
3372
		}
3373
	}
3374
	return $results;
3375
}
3376

    
3377
// Convert IPv6 addresses to lower case
3378
function addrtolower($ip) {
3379
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3380
		return(strtolower($ip));
3381
	} else {
3382
		return($ip);
3383
	}
3384
}
3385

    
3386
function compare_by_name($a, $b) {
3387
	return strcasecmp($a['name'], $b['name']);
3388
}
3389
?>
(38-38/60)