Project

General

Profile

Download (94.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
	    "hw.e6000sw.default_disabled", "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
		$skip = false;
1178
		list($name, $value) = explode('=', $line, 2);
1179
		foreach($remove as $rid => $rkey) {
1180
			if (strncasecmp(trim($name), $rkey, strlen($rkey)) == 0) {
1181
				$skip = true;
1182
				break;
1183
			}
1184
		}
1185
		if (!$skip) {
1186
			$data[] = $line;
1187
		}
1188
	}
1189

    
1190
	return ($data);
1191
}
1192

    
1193
function setup_loader_settings($path = "", $upgrade = false) {
1194
	global $g, $config;
1195

    
1196
	$boot_config_file = "{$path}/boot.config";
1197
	$loader_conf_file = "{$path}/boot/loader.conf";
1198

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

    
1201
	$vga_only = false;
1202
	$hdmi_only = false;
1203
	$serial_only = false;
1204
	$specific_platform = system_identify_specific_platform();
1205
	if ($specific_platform['name'] == 'XG-1540') {
1206
		$vga_only = true;
1207
	} elseif ($specific_platform['name'] == 'Turbot Dual-E') {
1208
		$hdmi_only = true;
1209
	} elseif ($specific_platform['name'] == 'RCC-VE' ||
1210
	    $specific_platform['name'] == 'RCC' ||
1211
	    $specific_platform['name'] == 'SG-2220' ||
1212
	    $specific_platform['name'] == 'apu2') {
1213
		$serial_only = true;
1214
	}
1215

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

    
1237
	if (empty($data)) {
1238
		@unlink($boot_conf_file);
1239
	} else {
1240
		safe_write_file($boot_config_file, $data);
1241
	}
1242
	unset($data, $boot_config, $boot_config_file, $boot_config_split);
1243

    
1244
	/* Serial console - write out /boot/loader.conf */
1245
	if ($upgrade) {
1246
		system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1247
	}
1248

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

    
1273
	if ($specific_platform['name'] == 'RCC-VE' ||
1274
	    $specific_platform['name'] == 'RCC' ||
1275
	    $specific_platform['name'] == 'SG-2220') {
1276
		$data[] = 'comconsole_port="0x2F8"';
1277
		$data[] = 'hint.uart.0.flags="0x00"';
1278
		$data[] = 'hint.uart.1.flags="0x10"';
1279
	}
1280
	$data[] = 'autoboot_delay="3"';
1281
	$data[] = 'hw.usb.no_pf="1"';
1282
	if (isset($config['system']['pti_disabled'])) {
1283
		$data[] = 'vm.pmap.pti="0"';
1284
	}
1285

    
1286
	safe_write_file($loader_conf_file, $data);
1287

    
1288
	/* Filter loader.conf.local to avoid duplicate settings. */
1289
	$loader_conf_file = "{$path}/boot/loader.conf.local";
1290
	$data = load_loader_conf($loader_conf_file, true);
1291
	if (empty($data)) {
1292
		@unlink($loader_conf_file);
1293
	} else {
1294
		safe_write_file($loader_conf_file, $data);
1295
	}
1296

    
1297
}
1298

    
1299
function setup_serial_port($when = "save", $path = "") {
1300
	global $config;
1301
	$ttys_file = "{$path}/etc/ttys";
1302

    
1303
	/* Update the loader settings. */
1304
	setup_loader_settings($path, ($when == "upgrade"));
1305

    
1306
	$ttys = file_get_contents($ttys_file);
1307
	$ttys_split = explode("\n", $ttys);
1308

    
1309
	$data = array();
1310

    
1311
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1312

    
1313
	if (isset($config['system']['disableconsolemenu'])) {
1314
		$console_type = 'Pc';
1315
		$serial_type = '3wire';
1316
	} else {
1317
		$console_type = 'al.Pc';
1318
		$serial_type = 'al.3wire';
1319
	}
1320

    
1321
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1322
	$ttyv0_line =
1323
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\txterm\ton\tsecure";
1324
	$ttyu_line =
1325
	    "\"/usr/libexec/getty {$serial_type}\"\tvt100\t{$on_off}\tsecure";
1326

    
1327
	$found = array();
1328

    
1329
	foreach ($ttys_split as $tty) {
1330
		/* Ignore blank lines */
1331
		if (empty($tty)) {
1332
			continue;
1333
		}
1334

    
1335
		if (stristr($tty, "ttyv0")) {
1336
			$found['ttyv0'] = 1;
1337
			$data[] = $ttyv0_line;
1338
		} elseif (stristr($tty, "ttyu")) {
1339
			$ttyn = substr($tty, 0, 5);
1340
			$found[$ttyn] = 1;
1341
			$data[] = "{$ttyn}\t{$ttyu_line}";
1342
		} elseif (substr($tty, 0, 7) == 'console') {
1343
			$found['console'] = 1;
1344
			$data[] = $tty;
1345
		} else {
1346
			$data[] = $tty;
1347
		}
1348
	}
1349
	unset($on_off, $console_type, $serial_type);
1350

    
1351
	/* Detect missing main lines on original file and try to rebuild it */
1352
	$items = array(
1353
		'console',
1354
		'ttyv0',
1355
		'ttyu0',
1356
		'ttyu1',
1357
		'ttyu2',
1358
		'ttyu3'
1359
	);
1360

    
1361
	foreach ($items as $item) {
1362
		if (isset($found[$item])) {
1363
			continue;
1364
		}
1365

    
1366
		if ($item == 'console') {
1367
			$data[] = $console_line;
1368
		} elseif ($item == 'ttyv0') {
1369
			$data[] = $ttyv0_line;
1370
		} else {
1371
			$data[] = "{$item}\t{$ttyu_line}";
1372
		}
1373
	}
1374

    
1375
	safe_write_file($ttys_file, $data);
1376

    
1377
	unset($ttys, $ttys_file, $ttys_split, $data);
1378

    
1379
	if ($when != "upgrade") {
1380
		reload_ttys();
1381
	}
1382

    
1383
	return;
1384
}
1385

    
1386
function is_serial_enabled() {
1387
	global $g, $config;
1388

    
1389
	if (!isset($g['enableserial_force']) &&
1390
	    !isset($config['system']['enableserial'])) {
1391
		return false;
1392
	}
1393

    
1394
	return true;
1395
}
1396

    
1397
function reload_ttys() {
1398
	// Send a HUP signal to init will make it reload /etc/ttys
1399
	posix_kill(1, SIGHUP);
1400
}
1401

    
1402
function print_value_list($list, $count = 10, $separator = ",") {
1403
	$list = implode($separator, array_slice($list, 0, $count));
1404
	if (count($list) < $count) {
1405
		$list .= ".";
1406
	} else {
1407
		$list .= "...";
1408
	}
1409
	return $list;
1410
}
1411

    
1412
/* DHCP enabled on any interfaces? */
1413
function is_dhcp_server_enabled() {
1414
	global $config;
1415

    
1416
	if (!is_array($config['dhcpd'])) {
1417
		return false;
1418
	}
1419

    
1420
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1421
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1422
			return true;
1423
		}
1424
	}
1425

    
1426
	return false;
1427
}
1428

    
1429
/* DHCP enabled on any interfaces? */
1430
function is_dhcpv6_server_enabled() {
1431
	global $config;
1432

    
1433
	if (is_array($config['interfaces'])) {
1434
		foreach ($config['interfaces'] as $ifcfg) {
1435
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1436
				return true;
1437
			}
1438
		}
1439
	}
1440

    
1441
	if (!is_array($config['dhcpdv6'])) {
1442
		return false;
1443
	}
1444

    
1445
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1446
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1447
			return true;
1448
		}
1449
	}
1450

    
1451
	return false;
1452
}
1453

    
1454
/* radvd enabled on any interfaces? */
1455
function is_radvd_enabled() {
1456
	global $config;
1457

    
1458
	if (!is_array($config['dhcpdv6'])) {
1459
		$config['dhcpdv6'] = array();
1460
	}
1461

    
1462
	$dhcpdv6cfg = $config['dhcpdv6'];
1463
	$Iflist = get_configured_interface_list();
1464

    
1465
	/* handle manually configured DHCP6 server settings first */
1466
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1467
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1468
			continue;
1469
		}
1470

    
1471
		if (!isset($dhcpv6ifconf['ramode'])) {
1472
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1473
		}
1474

    
1475
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1476
			continue;
1477
		}
1478

    
1479
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1480
		if (!is_ipaddrv6($ifcfgipv6)) {
1481
			continue;
1482
		}
1483

    
1484
		return true;
1485
	}
1486

    
1487
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1488
	foreach ($Iflist as $if => $ifdescr) {
1489
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1490
			continue;
1491
		}
1492
		if (!isset($config['interfaces'][$if]['enable'])) {
1493
			continue;
1494
		}
1495

    
1496
		$ifcfgipv6 = get_interface_ipv6($if);
1497
		if (!is_ipaddrv6($ifcfgipv6)) {
1498
			continue;
1499
		}
1500

    
1501
		$ifcfgsnv6 = get_interface_subnetv6($if);
1502
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1503

    
1504
		if (!is_ipaddrv6($subnetv6)) {
1505
			continue;
1506
		}
1507

    
1508
		return true;
1509
	}
1510

    
1511
	return false;
1512
}
1513

    
1514
/* Any PPPoE servers enabled? */
1515
function is_pppoe_server_enabled() {
1516
	global $config;
1517

    
1518
	$pppoeenable = false;
1519

    
1520
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1521
		return false;
1522
	}
1523

    
1524
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1525
		if ($pppoes['mode'] == 'server') {
1526
			$pppoeenable = true;
1527
		}
1528
	}
1529

    
1530
	return $pppoeenable;
1531
}
1532

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

    
1547
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1548

    
1549
function get_ppp_uptime($port) {
1550
	if (file_exists("/conf/{$port}.log")) {
1551
		$saved_time = file_get_contents("/conf/{$port}.log");
1552
		$uptime_data = explode("\n", $saved_time);
1553
		$sec = 0;
1554
		foreach ($uptime_data as $upt) {
1555
			$sec += substr($upt, 1 + strpos($upt, " "));
1556
		}
1557
		return convert_seconds_to_dhms($sec);
1558
	} else {
1559
		$total_time = gettext("No history data found!");
1560
		return $total_time;
1561
	}
1562
}
1563

    
1564
//returns interface information
1565
function get_interface_info($ifdescr) {
1566
	global $config, $g;
1567

    
1568
	$ifinfo = array();
1569
	if (empty($config['interfaces'][$ifdescr])) {
1570
		return;
1571
	}
1572
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1573
	$ifinfo['enable'] = isset($config['interfaces'][$ifdescr]['enable']);
1574
	$ifinfo['if'] = get_real_interface($ifdescr);
1575

    
1576
	$chkif = $ifinfo['if'];
1577
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1578
	$ifinfo['status'] = $ifinfotmp['status'];
1579
	if (empty($ifinfo['status'])) {
1580
		$ifinfo['status'] = "down";
1581
	}
1582
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1583
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1584
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1585
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1586
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1587
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1588
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1589
	if (isset($ifinfotmp['link0'])) {
1590
		$link0 = "down";
1591
	}
1592
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1593
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1594
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1595
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1596
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1597
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1598

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

    
1619
	/* Block */
1620
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1621
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1622
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1623
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1624
	$in4_block = $pf_in4_block[5];
1625
	$out4_block = $pf_out4_block[5];
1626
	$in4_block_packets = $pf_in4_block[3];
1627
	$out4_block_packets = $pf_out4_block[3];
1628
	$in6_block = $pf_in6_block[5];
1629
	$out6_block = $pf_out6_block[5];
1630
	$in6_block_packets = $pf_in6_block[3];
1631
	$out6_block_packets = $pf_out6_block[3];
1632
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1633
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1634
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1635
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1636

    
1637
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1638
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1639
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1640
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1641

    
1642
	$ifconfiginfo = "";
1643
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1644
	switch ($link_type) {
1645
		/* DHCP? -> see if dhclient is up */
1646
		case "dhcp":
1647
			/* see if dhclient is up */
1648
			if (find_dhclient_process($ifinfo['if']) != 0) {
1649
				$ifinfo['dhcplink'] = "up";
1650
			} else {
1651
				$ifinfo['dhcplink'] = "down";
1652
			}
1653

    
1654
			break;
1655
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1656
		case "pppoe":
1657
		case "pptp":
1658
		case "l2tp":
1659
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1660
				/* get PPPoE link status for dial on demand */
1661
				$ifinfo["{$link_type}link"] = "up";
1662
			} else {
1663
				$ifinfo["{$link_type}link"] = "down";
1664
			}
1665

    
1666
			break;
1667
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1668
		case "ppp":
1669
			if ($ifinfo['status'] == "up") {
1670
				$ifinfo['ppplink'] = "up";
1671
			} else {
1672
				$ifinfo['ppplink'] = "down" ;
1673
			}
1674

    
1675
			if (empty($ifinfo['status'])) {
1676
				$ifinfo['status'] = "down";
1677
			}
1678

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

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

    
1730
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1731
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1732
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1733
	}
1734

    
1735
	if ($ifinfo['status'] == "up") {
1736
		/* try to determine media with ifconfig */
1737
		unset($ifconfiginfo);
1738
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1739
		$wifconfiginfo = array();
1740
		if (is_interface_wireless($ifdescr)) {
1741
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1742
			array_shift($wifconfiginfo);
1743
		}
1744
		$matches = "";
1745
		foreach ($ifconfiginfo as $ici) {
1746

    
1747
			/* don't list media/speed for wireless cards, as it always
1748
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1749
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1750
				$ifinfo['media'] = $matches[1];
1751
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1752
				$ifinfo['media'] = $matches[1];
1753
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1754
				$ifinfo['media'] = $matches[1];
1755
			}
1756

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

    
1802
	$bridge = "";
1803
	$bridge = link_interface_to_bridge($ifdescr);
1804
	if ($bridge) {
1805
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1806
		if (stristr($bridge_text, "blocking") <> false) {
1807
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1808
			$ifinfo['bridgeint'] = $bridge;
1809
		} else if (stristr($bridge_text, "learning") <> false) {
1810
			$ifinfo['bridge'] = gettext("learning");
1811
			$ifinfo['bridgeint'] = $bridge;
1812
		} else if (stristr($bridge_text, "forwarding") <> false) {
1813
			$ifinfo['bridge'] = gettext("forwarding");
1814
			$ifinfo['bridgeint'] = $bridge;
1815
		}
1816
	}
1817

    
1818
	return $ifinfo;
1819
}
1820

    
1821
//returns cpu speed of processor. Good for determining capabilities of machine
1822
function get_cpu_speed() {
1823
	return get_single_sysctl("hw.clockrate");
1824
}
1825

    
1826
function get_uptime_sec() {
1827
	$boottime = "";
1828
	$matches = "";
1829
	$boottime = get_single_sysctl("kern.boottime");
1830
	preg_match("/sec = (\d+)/", $boottime, $matches);
1831
	$boottime = $matches[1];
1832
	if (intval($boottime) == 0) {
1833
		return 0;
1834
	}
1835

    
1836
	$uptime = time() - $boottime;
1837
	return $uptime;
1838
}
1839

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

    
1873
function is_fqdn($fqdn) {
1874
	$hostname = false;
1875
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1876
		$hostname = true;
1877
	}
1878
	if (preg_match("/\.\./", $fqdn)) {
1879
		$hostname = false;
1880
	}
1881
	if (preg_match("/^\./i", $fqdn)) {
1882
		$hostname = false;
1883
	}
1884
	if (preg_match("/\//i", $fqdn)) {
1885
		$hostname = false;
1886
	}
1887
	return($hostname);
1888
}
1889

    
1890
function pfsense_default_state_size() {
1891
	/* get system memory amount */
1892
	$memory = get_memory();
1893
	$physmem = $memory[0];
1894
	/* Be cautious and only allocate 10% of system memory to the state table */
1895
	$max_states = (int) ($physmem/10)*1000;
1896
	return $max_states;
1897
}
1898

    
1899
function pfsense_default_tables_size() {
1900
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1901
	return $current;
1902
}
1903

    
1904
function pfsense_default_table_entries_size() {
1905
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1906
	return (trim($current));
1907
}
1908

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

    
1945
	if (trim($oldcontents) != trim($contents)) {
1946
		if ($g['debug']) {
1947
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1948
		}
1949
		return ($oldcontents);
1950
	} else {
1951
		return false;
1952
	}
1953
}
1954

    
1955
/*
1956
 * load_crypto() - Load crypto modules if enabled in config.
1957
 */
1958
function load_crypto() {
1959
	global $config, $g;
1960
	$crypto_modules = array('aesni', 'cryptodev');
1961

    
1962
	$enabled_modules = explode('_', $config['system']['crypto_hardware']);
1963

    
1964
	foreach ($enabled_modules as $enmod) {
1965
		if (empty($enmod) || !in_array($enmod, $crypto_modules)) {
1966
			continue;
1967
		}
1968
		if (!is_module_loaded($enmod)) {
1969
			log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $enmod));
1970
			mwexec("/sbin/kldload " . escapeshellarg($enmod));
1971
		}
1972
	}
1973
}
1974

    
1975
/*
1976
 * load_thermal_hardware() - Load temperature monitor kernel module
1977
 */
1978
function load_thermal_hardware() {
1979
	global $config, $g;
1980
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1981

    
1982
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1983
		return false;
1984
	}
1985

    
1986
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1987
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1988
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1989
	}
1990
}
1991

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

    
2004
	if ($rc != 0 || !isset($output[0])) {
2005
		return false;
2006
	}
2007

    
2008
	foreach ($virtualenvs as $virtualenv) {
2009
		if (stripos($output[0], $virtualenv) !== false) {
2010
			return true;
2011
		}
2012
	}
2013

    
2014
	return false;
2015
}
2016

    
2017
function get_freebsd_version() {
2018
	$version = explode(".", php_uname("r"));
2019
	return $version[0];
2020
}
2021

    
2022
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
2023
	global $config, $g;
2024

    
2025
	$fp = fopen($destination, "wb");
2026

    
2027
	if (!$fp) {
2028
		return false;
2029
	}
2030

    
2031
	$ch = curl_init();
2032
	curl_setopt($ch, CURLOPT_URL, $url);
2033
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
2034
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2035
	curl_setopt($ch, CURLOPT_FILE, $fp);
2036
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2037
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2038
	curl_setopt($ch, CURLOPT_HEADER, false);
2039
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2040
	if (!isset($config['system']['do_not_send_uniqueid'])) {
2041
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
2042
	} else {
2043
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2044
	}
2045

    
2046
	if (!empty($config['system']['proxyurl'])) {
2047
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2048
		if (!empty($config['system']['proxyport'])) {
2049
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2050
		}
2051
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2052
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2053
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2054
		}
2055
	}
2056

    
2057
	@curl_exec($ch);
2058
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2059
	fclose($fp);
2060
	curl_close($ch);
2061
	if ($http_code == 200) {
2062
		return true;
2063
	} else {
2064
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2065
		unlink_if_exists($destination);
2066
		return false;
2067
	}
2068
}
2069

    
2070
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
2071
	global $config, $g;
2072
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
2073
	$file_size = 1;
2074
	$downloaded = 1;
2075
	$first_progress_update = TRUE;
2076
	/* open destination file */
2077
	$fout = fopen($destination, "wb");
2078

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

    
2102
	if (!empty($config['system']['proxyurl'])) {
2103
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2104
		if (!empty($config['system']['proxyport'])) {
2105
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2106
		}
2107
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2108
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2109
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2110
		}
2111
	}
2112

    
2113
	@curl_exec($ch);
2114
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2115
	fclose($fout);
2116
	curl_close($ch);
2117
	if ($http_code == 200) {
2118
		return true;
2119
	} else {
2120
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2121
		unlink_if_exists($destination);
2122
		return false;
2123
	}
2124
}
2125

    
2126
function read_header($ch, $string) {
2127
	global $file_size, $fout;
2128
	$length = strlen($string);
2129
	$regs = "";
2130
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
2131
	if ($regs[2] <> "") {
2132
		$file_size = intval($regs[2]);
2133
	}
2134
	ob_flush();
2135
	return $length;
2136
}
2137

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

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

    
2210
/*
2211
 *   update_status: update top textarea dynamically.
2212
 */
2213
function update_status($status) {
2214
	global $pkg_interface;
2215

    
2216
	if ($pkg_interface == "console") {
2217
		print ("{$status}");
2218
	}
2219

    
2220
	/* ensure that contents are written out */
2221
	ob_flush();
2222
}
2223

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

    
2246
function update_alias_name($new_alias_name, $orig_alias_name) {
2247
	if (!$orig_alias_name) {
2248
		return;
2249
	}
2250

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

    
2277
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2278
	global $g, $config, $pconfig, $debug;
2279
	if (!$origname) {
2280
		return;
2281
	}
2282

    
2283
	$sectionref = &$config;
2284
	foreach ($section as $sectionname) {
2285
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2286
			$sectionref = &$sectionref[$sectionname];
2287
		} else {
2288
			return;
2289
		}
2290
	}
2291

    
2292
	if ($debug) {
2293
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2294
		fwrite($fd, print_r($pconfig, true));
2295
	}
2296

    
2297
	if (is_array($sectionref)) {
2298
		foreach ($sectionref as $itemkey => $item) {
2299
			if ($debug) {
2300
				fwrite($fd, "$itemkey\n");
2301
			}
2302

    
2303
			$fieldfound = true;
2304
			$fieldref = &$sectionref[$itemkey];
2305
			foreach ($field as $fieldname) {
2306
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2307
					$fieldref = &$fieldref[$fieldname];
2308
				} else {
2309
					$fieldfound = false;
2310
					break;
2311
				}
2312
			}
2313
			if ($fieldfound && $fieldref == $origname) {
2314
				if ($debug) {
2315
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2316
				}
2317
				$fieldref = $new_alias_name;
2318
			}
2319
		}
2320
	}
2321

    
2322
	if ($debug) {
2323
		fclose($fd);
2324
	}
2325

    
2326
}
2327

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

    
2338
	if (!file_exists($filename)) {
2339
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2340
		return null;
2341
	}
2342

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

    
2385
function update_alias_url_data() {
2386
	global $config, $g;
2387

    
2388
	$updated = false;
2389

    
2390
	/* item is a url type */
2391
	$lockkey = lock('aliasurl');
2392
	if (is_array($config['aliases']['alias'])) {
2393
		foreach ($config['aliases']['alias'] as $x => $alias) {
2394
			if (empty($alias['aliasurl'])) {
2395
				continue;
2396
			}
2397

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

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

    
2429
	/* Report status to callers as well */
2430
	return $updated;
2431
}
2432

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

    
2463
	return true;
2464
}
2465

    
2466
function version_compare_dates($a, $b) {
2467
	$a_time = strtotime($a);
2468
	$b_time = strtotime($b);
2469

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

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

    
2554
		// First try to compare the numeric parts of the version string.
2555
		$v = version_compare_numeric($cur_num, $rem_num);
2556

    
2557
		// If the numeric parts are the same, compare the string parts.
2558
		if ($v == 0) {
2559
			return version_compare_string($cur_str, $rem_str);
2560
		}
2561
	}
2562
	return $v;
2563
}
2564
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2565
	global $g, $config;
2566

    
2567
	$urltable_prefix = "/var/db/aliastables/";
2568
	$urltable_filename = $urltable_prefix . $name . ".txt";
2569
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2570

    
2571
	// Make the aliases directory if it doesn't exist
2572
	if (!file_exists($urltable_prefix)) {
2573
		mkdir($urltable_prefix);
2574
	} elseif (!is_dir($urltable_prefix)) {
2575
		unlink($urltable_prefix);
2576
		mkdir($urltable_prefix);
2577
	}
2578

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

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

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

    
2593
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2594
			if ($type == "urltable_ports") {
2595
				$parsed_contents = group_ports($parsed_contents, true);
2596
			}
2597
			if (is_array($parsed_contents)) {
2598
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2599
			} else {
2600
				touch($urltable_filename);
2601
			}
2602

    
2603
			/* Remove existing archive and create an up to date archive if RAM disk is enabled. */
2604
			unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz");
2605
			if (isset($config['system']['use_mfs_tmpvar'])) {
2606
				mwexec("/usr/bin/tar -czf " . escapeshellarg("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz") . " -C / " . escapeshellarg($urltable_filename));
2607
			}
2608

    
2609
			unlink_if_exists($tmp_urltable_filename);
2610
		} else {
2611
			if (!$validateonly) {
2612
				touch($urltable_filename);
2613
			}
2614
			return false;
2615
		}
2616
		return true;
2617
	} else {
2618
		// File exists, and it doesn't need to be updated.
2619
		return -1;
2620
	}
2621
}
2622

    
2623
function get_include_contents($filename) {
2624
	if (is_file($filename)) {
2625
		ob_start();
2626
		include $filename;
2627
		$contents = ob_get_contents();
2628
		ob_end_clean();
2629
		return $contents;
2630
	}
2631
	return false;
2632
}
2633

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

    
2746
function get_country_name($country_code) {
2747
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2748
		return "";
2749
	}
2750

    
2751
	$country_names_xml = "/usr/local/share/pfSense/iso_3166-1_list_en.xml";
2752
	$country_names_contents = file_get_contents($country_names_xml);
2753
	$country_names = xml2array($country_names_contents);
2754

    
2755
	if ($country_code == "ALL") {
2756
		$country_list = array();
2757
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2758
			$country_list[] = array(
2759
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2760
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2761
		}
2762
		return $country_list;
2763
	}
2764

    
2765
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2766
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2767
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2768
		}
2769
	}
2770
	return "";
2771
}
2772

    
2773
/* sort by interface only, retain the original order of rules that apply to
2774
   the same interface */
2775
function filter_rules_sort() {
2776
	global $config;
2777

    
2778
	/* mark each rule with the sequence number (to retain the order while sorting) */
2779
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2780
		if (!is_array($config['filter']['rule'][$i])) {
2781
			$config['filter']['rule'][$i] = array();
2782
		}
2783
		$config['filter']['rule'][$i]['seq'] = $i;
2784
	}
2785

    
2786
	usort($config['filter']['rule'], "filter_rules_compare");
2787

    
2788
	/* strip the sequence numbers again */
2789
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2790
		unset($config['filter']['rule'][$i]['seq']);
2791
	}
2792
}
2793
function filter_rules_compare($a, $b) {
2794
	if (isset($a['floating']) && isset($b['floating'])) {
2795
		return $a['seq'] - $b['seq'];
2796
	} else if (isset($a['floating'])) {
2797
		return -1;
2798
	} else if (isset($b['floating'])) {
2799
		return 1;
2800
	} else if ($a['interface'] == $b['interface']) {
2801
		return $a['seq'] - $b['seq'];
2802
	} else {
2803
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2804
	}
2805
}
2806

    
2807
function generate_ipv6_from_mac($mac) {
2808
	$elements = explode(":", $mac);
2809
	if (count($elements) <> 6) {
2810
		return false;
2811
	}
2812

    
2813
	$i = 0;
2814
	$ipv6 = "fe80::";
2815
	foreach ($elements as $byte) {
2816
		if ($i == 0) {
2817
			$hexadecimal = substr($byte, 1, 2);
2818
			$bitmap = base_convert($hexadecimal, 16, 2);
2819
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2820
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2821
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2822
		}
2823
		$ipv6 .= $byte;
2824
		if ($i == 1) {
2825
			$ipv6 .= ":";
2826
		}
2827
		if ($i == 3) {
2828
			$ipv6 .= ":";
2829
		}
2830
		if ($i == 2) {
2831
			$ipv6 .= "ff:fe";
2832
		}
2833

    
2834
		$i++;
2835
	}
2836
	return $ipv6;
2837
}
2838

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

    
2865
}
2866

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

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

    
2906
	$where_configured = array();
2907

    
2908
	$pos = strpos($ignore_if, '_virtualip');
2909
	if ($pos !== false) {
2910
		$ignore_vip_id = substr($ignore_if, $pos+10);
2911
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2912
	} else {
2913
		$ignore_vip_id = -1;
2914
		$ignore_vip_if = $ignore_if;
2915
	}
2916

    
2917
	$isipv6 = is_ipaddrv6($ipaddr);
2918

    
2919
	if ($isipv6) {
2920
		$ipaddr = text_to_compressed_ip6($ipaddr);
2921
	}
2922

    
2923
	if ($check_subnets) {
2924
		$cidrprefix = intval($cidrprefix);
2925
		if ($isipv6) {
2926
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2927
				$cidrprefix = 128;
2928
			}
2929
		} else {
2930
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2931
				$cidrprefix = 32;
2932
			}
2933
		}
2934
		$iflist = get_configured_interface_list();
2935
		foreach ($iflist as $if => $ifname) {
2936
			if ($ignore_if == $if) {
2937
				continue;
2938
			}
2939

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

    
2967
		foreach ($interface_list_ips as $if => $ilips) {
2968
			if ($ignore_if == $if) {
2969
				continue;
2970
			}
2971
			if (strcasecmp($ipaddr, $ilips) == 0) {
2972
				$where_entry = array();
2973
				$where_entry['if'] = $if;
2974
				$where_entry['ip_or_subnet'] = $ilips;
2975
				$where_configured[] = $where_entry;
2976
			}
2977
		}
2978
	}
2979

    
2980
	if ($check_localip) {
2981
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, text_to_compressed_ip6($config['l2tp']['localip'])) == 0)) {
2982
			$where_entry = array();
2983
			$where_entry['if'] = 'l2tp';
2984
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
2985
			$where_configured[] = $where_entry;
2986
		}
2987
	}
2988

    
2989
	return $where_configured;
2990
}
2991

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

    
3014
function set_language() {
3015
	global $config, $g;
3016

    
3017
	if (!empty($config['system']['language'])) {
3018
		$lang = $config['system']['language'];
3019
	} elseif (!empty($g['language'])) {
3020
		$lang = $g['language'];
3021
	}
3022
	$lang .= ".UTF-8";
3023

    
3024
	putenv("LANG={$lang}");
3025
	setlocale(LC_ALL, $lang);
3026
	textdomain("pfSense");
3027
	bindtextdomain("pfSense", "/usr/local/share/locale");
3028
	bind_textdomain_codeset("pfSense", $lang);
3029
}
3030

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

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

    
3055
	//asort($locales);
3056

    
3057
	return $locales;
3058
}
3059

    
3060
function return_hex_ipv4($ipv4) {
3061
	if (!is_ipaddrv4($ipv4)) {
3062
		return(false);
3063
	}
3064

    
3065
	/* we need the hex form of the interface IPv4 address */
3066
	$ip4arr = explode(".", $ipv4);
3067
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
3068
}
3069

    
3070
function convert_ipv6_to_128bit($ipv6) {
3071
	if (!is_ipaddrv6($ipv6)) {
3072
		return(false);
3073
	}
3074

    
3075
	$ip6arr = array();
3076
	$ip6prefix = Net_IPv6::uncompress($ipv6);
3077
	$ip6arr = explode(":", $ip6prefix);
3078
	/* binary presentation of the prefix for all 128 bits. */
3079
	$ip6prefixbin = "";
3080
	foreach ($ip6arr as $element) {
3081
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3082
	}
3083
	return($ip6prefixbin);
3084
}
3085

    
3086
function convert_128bit_to_ipv6($ip6bin) {
3087
	if (strlen($ip6bin) <> 128) {
3088
		return(false);
3089
	}
3090

    
3091
	$ip6arr = array();
3092
	$ip6binarr = array();
3093
	$ip6binarr = str_split($ip6bin, 16);
3094
	foreach ($ip6binarr as $binpart) {
3095
		$ip6arr[] = dechex(bindec($binpart));
3096
	}
3097
	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
3098

    
3099
	return($ip6addr);
3100
}
3101

    
3102

    
3103
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3104
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3105
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3106
/* 6to4 is 16 bits, e.g. 65535 */
3107
function calculate_ipv6_delegation_length($if) {
3108
	global $config;
3109

    
3110
	if (!is_array($config['interfaces'][$if])) {
3111
		return false;
3112
	}
3113

    
3114
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3115
		case "6to4":
3116
			$pdlen = 16;
3117
			break;
3118
		case "6rd":
3119
			$rd6cfg = $config['interfaces'][$if];
3120
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3121
			$pdlen = (64 - ((int) $rd6plen[1] + (32 - (int) $rd6cfg['prefix-6rd-v4plen'])));
3122
			break;
3123
		case "dhcp6":
3124
			$dhcp6cfg = $config['interfaces'][$if];
3125
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3126
			break;
3127
		default:
3128
			$pdlen = 0;
3129
			break;
3130
	}
3131
	return($pdlen);
3132
}
3133

    
3134
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3135
	$prefix = Net_IPv6::uncompress($prefix, true);
3136
	$suffix = Net_IPv6::uncompress($suffix, true);
3137

    
3138
	/*
3139
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3140
	 *                ^^^^ ^
3141
	 *                |||| \-> 64
3142
	 *                |||\---> 63, 62, 61, 60
3143
	 *                ||\----> 56
3144
	 *                |\-----> 52
3145
	 *                \------> 48
3146
	 */
3147

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

    
3179
	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
3180
	    substr($suffix, $prefix_len));
3181
}
3182

    
3183
function dhcpv6_pd_str_help($pdlen) {
3184
	$result = '';
3185

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

    
3218
	return $result;
3219
}
3220

    
3221
function huawei_rssi_to_string($rssi) {
3222
	$dbm = array();
3223
	$i = 0;
3224
	$dbstart = -113;
3225
	while ($i < 32) {
3226
		$dbm[$i] = $dbstart + ($i * 2);
3227
		$i++;
3228
	}
3229
	$percent = round(($rssi / 31) * 100);
3230
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3231
	return $string;
3232
}
3233

    
3234
function huawei_mode_to_string($mode, $submode) {
3235
	$modes[0] = gettext("None");
3236
	$modes[1] = "AMPS";
3237
	$modes[2] = "CDMA";
3238
	$modes[3] = "GSM/GPRS";
3239
	$modes[4] = "HDR";
3240
	$modes[5] = "WCDMA";
3241
	$modes[6] = "GPS";
3242

    
3243
	$submodes[0] = gettext("No Service");
3244
	$submodes[1] = "GSM";
3245
	$submodes[2] = "GPRS";
3246
	$submodes[3] = "EDGE";
3247
	$submodes[4] = "WCDMA";
3248
	$submodes[5] = "HSDPA";
3249
	$submodes[6] = "HSUPA";
3250
	$submodes[7] = "HSDPA+HSUPA";
3251
	$submodes[8] = "TD-SCDMA";
3252
	$submodes[9] = "HSPA+";
3253
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3254
	return $string;
3255
}
3256

    
3257
function huawei_service_to_string($state) {
3258
	$modes[0] = gettext("No Service");
3259
	$modes[1] = gettext("Restricted Service");
3260
	$modes[2] = gettext("Valid Service");
3261
	$modes[3] = gettext("Restricted Regional Service");
3262
	$modes[4] = gettext("Powersaving Service");
3263
	$modes[255] = gettext("Unknown Service");
3264
	$string = $modes[$state];
3265
	return $string;
3266
}
3267

    
3268
function huawei_simstate_to_string($state) {
3269
	$modes[0] = gettext("Invalid SIM/locked State");
3270
	$modes[1] = gettext("Valid SIM State");
3271
	$modes[2] = gettext("Invalid SIM CS State");
3272
	$modes[3] = gettext("Invalid SIM PS State");
3273
	$modes[4] = gettext("Invalid SIM CS/PS State");
3274
	$modes[255] = gettext("Missing SIM State");
3275
	$string = $modes[$state];
3276
	return $string;
3277
}
3278

    
3279
function zte_rssi_to_string($rssi) {
3280
	return huawei_rssi_to_string($rssi);
3281
}
3282

    
3283
function zte_mode_to_string($mode, $submode) {
3284
	$modes[0] = gettext("No Service");
3285
	$modes[1] = gettext("Limited Service");
3286
	$modes[2] = "GPRS";
3287
	$modes[3] = "GSM";
3288
	$modes[4] = "UMTS";
3289
	$modes[5] = "EDGE";
3290
	$modes[6] = "HSDPA";
3291

    
3292
	$submodes[0] = "CS_ONLY";
3293
	$submodes[1] = "PS_ONLY";
3294
	$submodes[2] = "CS_PS";
3295
	$submodes[3] = "CAMPED";
3296
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3297
	return $string;
3298
}
3299

    
3300
function zte_service_to_string($service) {
3301
	$modes[0] = gettext("Initializing Service");
3302
	$modes[1] = gettext("Network Lock error Service");
3303
	$modes[2] = gettext("Network Locked Service");
3304
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3305
	$string = $modes[$service];
3306
	return $string;
3307
}
3308

    
3309
function zte_simstate_to_string($state) {
3310
	$modes[0] = gettext("No action State");
3311
	$modes[1] = gettext("Network lock State");
3312
	$modes[2] = gettext("(U)SIM card lock State");
3313
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3314
	$string = $modes[$state];
3315
	return $string;
3316
}
3317

    
3318
function get_configured_pppoe_server_interfaces() {
3319
	global $config;
3320
	$iflist = array();
3321
	if (is_array($config['pppoes']['pppoe'])) {
3322
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3323
			if ($pppoe['mode'] == "server") {
3324
				$int = "poes". $pppoe['pppoeid'];
3325
				$iflist[$int] = strtoupper($int);
3326
			}
3327
		}
3328
	}
3329
	return $iflist;
3330
}
3331

    
3332
function get_pppoes_child_interfaces($ifpattern) {
3333
	$if_arr = array();
3334
	if ($ifpattern == "") {
3335
		return;
3336
	}
3337

    
3338
	exec("/sbin/ifconfig", $out, $ret);
3339
	foreach ($out as $line) {
3340
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3341
			$if_arr[] = $match[1];
3342
		}
3343
	}
3344
	return $if_arr;
3345

    
3346
}
3347

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

    
3384
// Convert IPv6 addresses to lower case
3385
function addrtolower($ip) {
3386
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3387
		return(strtolower($ip));
3388
	} else {
3389
		return($ip);
3390
	}
3391
}
3392

    
3393
function compare_by_name($a, $b) {
3394
	return strcasecmp($a['name'], $b['name']);
3395
}
3396

    
3397
/****f* pfsense-utils/getarraybyref
3398
 * NAME
3399
 *   getarraybyref
3400
 * INPUTS
3401
 *   $array the array of which a items array needs to be found. 
3402
 *   $args.. the sub-items to be retrieved/created
3403
 * RESULT
3404
 *   returns the array that was retrieved from configuration, its created if it does not exist
3405
 * NOTES
3406
 *   Used by haproxy / acme / others.?. . 
3407
 *   can be used like this:  $a_certificates = getarraybyref($config, 'installedpackages', 'acme', 'certificates', 'item');
3408
 ******/
3409
function &getarraybyref(&$array) {
3410
	if (!isset($array)) {
3411
		return false;
3412
	}
3413
	if (!is_array($array)) {
3414
		$array = array();
3415
	}
3416
	$item = &$array;
3417
	$arg = func_get_args();
3418
	for($i = 1; $i < count($arg); $i++) {
3419
		$itemindex = $arg[$i];
3420
		if (!is_array($item[$itemindex])) {
3421
			$item[$itemindex] = array();
3422
		}
3423
		$item = &$item[$itemindex];
3424
	}
3425
	return $item;
3426
}
3427

    
3428
?>
(38-38/60)