Project

General

Profile

Download (95.3 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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1209
	return ($data);
1210
}
1211

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

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

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

    
1220
	$vga_only = false;
1221
	$hdmi_only = false;
1222
	$serial_only = false;
1223
	$specific_platform = system_identify_specific_platform();
1224
	if ($specific_platform['name'] == 'XG-1540') {
1225
		$vga_only = true;
1226
	} elseif ($specific_platform['name'] == 'Turbot Dual-E') {
1227
		$hdmi_only = true;
1228
	} elseif ($specific_platform['name'] == 'RCC-VE' ||
1229
	    $specific_platform['name'] == 'RCC' ||
1230
	    $specific_platform['name'] == 'SG-2220' ||
1231
	    $specific_platform['name'] == 'apu2') {
1232
		$serial_only = true;
1233
	}
1234

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

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

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

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

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

    
1305
	safe_write_file($loader_conf_file, $data);
1306

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

    
1316
}
1317

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

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

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

    
1328
	$data = array();
1329

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

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

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

    
1346
	$found = array();
1347

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

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

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

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

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

    
1394
	safe_write_file($ttys_file, $data);
1395

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

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

    
1402
	return;
1403
}
1404

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

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

    
1413
	return true;
1414
}
1415

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

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

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

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

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

    
1445
	return false;
1446
}
1447

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

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

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

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

    
1470
	return false;
1471
}
1472

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

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

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

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

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

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

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

    
1503
		return true;
1504
	}
1505

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

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

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

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

    
1527
		return true;
1528
	}
1529

    
1530
	return false;
1531
}
1532

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

    
1537
	$pppoeenable = false;
1538

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

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

    
1549
	return $pppoeenable;
1550
}
1551

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1837
	return $ifinfo;
1838
}
1839

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2033
	return false;
2034
}
2035

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2345
}
2346

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

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

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

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

    
2407
	$updated = false;
2408

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

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

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

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

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

    
2482
	return true;
2483
}
2484

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2792
/* sort by interface only, retain the original order of rules that apply to
2793
   the same interface */
2794
function filter_rules_sort() {
2795
	global $config;
2796

    
2797
	/* mark each rule with the sequence number (to retain the order while sorting) */
2798
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2799
		if (!is_array($config['filter']['rule'][$i])) {
2800
			$config['filter']['rule'][$i] = array();
2801
		}
2802
		$config['filter']['rule'][$i]['seq'] = $i;
2803
	}
2804

    
2805
	usort($config['filter']['rule'], "filter_rules_compare");
2806

    
2807
	/* strip the sequence numbers again */
2808
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2809
		unset($config['filter']['rule'][$i]['seq']);
2810
	}
2811
}
2812
function filter_rules_compare($a, $b) {
2813
	if (isset($a['floating']) && isset($b['floating'])) {
2814
		return $a['seq'] - $b['seq'];
2815
	} else if (isset($a['floating'])) {
2816
		return -1;
2817
	} else if (isset($b['floating'])) {
2818
		return 1;
2819
	} else if ($a['interface'] == $b['interface']) {
2820
		return $a['seq'] - $b['seq'];
2821
	} else {
2822
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2823
	}
2824
}
2825

    
2826
function generate_ipv6_from_mac($mac) {
2827
	$elements = explode(":", $mac);
2828
	if (count($elements) <> 6) {
2829
		return false;
2830
	}
2831

    
2832
	$i = 0;
2833
	$ipv6 = "fe80::";
2834
	foreach ($elements as $byte) {
2835
		if ($i == 0) {
2836
			$hexadecimal = substr($byte, 1, 2);
2837
			$bitmap = base_convert($hexadecimal, 16, 2);
2838
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2839
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2840
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2841
		}
2842
		$ipv6 .= $byte;
2843
		if ($i == 1) {
2844
			$ipv6 .= ":";
2845
		}
2846
		if ($i == 3) {
2847
			$ipv6 .= ":";
2848
		}
2849
		if ($i == 2) {
2850
			$ipv6 .= "ff:fe";
2851
		}
2852

    
2853
		$i++;
2854
	}
2855
	return $ipv6;
2856
}
2857

    
2858
/****f* pfsense-utils/load_mac_manufacturer_table
2859
 * NAME
2860
 *   load_mac_manufacturer_table
2861
 * INPUTS
2862
 *   none
2863
 * RESULT
2864
 *   returns associative array with MAC-Manufacturer pairs
2865
 ******/
2866
function load_mac_manufacturer_table() {
2867
	/* load MAC-Manufacture data from the file */
2868
	$macs = false;
2869
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2870
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2871
	}
2872
	if ($macs) {
2873
		foreach ($macs as $line) {
2874
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2875
				/* store values like this $mac_man['000C29']='VMware' */
2876
				$mac_man["$matches[1]"] = $matches[2];
2877
			}
2878
		}
2879
		return $mac_man;
2880
	} else {
2881
		return -1;
2882
	}
2883

    
2884
}
2885

    
2886
/****f* pfsense-utils/is_ipaddr_configured
2887
 * NAME
2888
 *   is_ipaddr_configured
2889
 * INPUTS
2890
 *   IP Address to check.
2891
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2892
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2893
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2894
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2895
 *     If check_subnets is true and cidrprefix is specified,
2896
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2897
 * RESULT
2898
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2899
*/
2900
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2901
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2902
		return true;
2903
	}
2904
	return false;
2905
}
2906

    
2907
/****f* pfsense-utils/where_is_ipaddr_configured
2908
 * NAME
2909
 *   where_is_ipaddr_configured
2910
 * INPUTS
2911
 *   IP Address to check.
2912
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2913
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2914
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2915
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2916
 *     If check_subnets is true and cidrprefix is specified,
2917
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2918
 * RESULT
2919
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2920
 *   If there are no matches then an empty array is returned.
2921
*/
2922
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2923
	global $config;
2924

    
2925
	$where_configured = array();
2926

    
2927
	$pos = strpos($ignore_if, '_virtualip');
2928
	if ($pos !== false) {
2929
		$ignore_vip_id = substr($ignore_if, $pos+10);
2930
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2931
	} else {
2932
		$ignore_vip_id = -1;
2933
		$ignore_vip_if = $ignore_if;
2934
	}
2935

    
2936
	$isipv6 = is_ipaddrv6($ipaddr);
2937

    
2938
	if ($isipv6) {
2939
		$ipaddr = text_to_compressed_ip6($ipaddr);
2940
	}
2941

    
2942
	if ($check_subnets) {
2943
		$cidrprefix = intval($cidrprefix);
2944
		if ($isipv6) {
2945
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2946
				$cidrprefix = 128;
2947
			}
2948
		} else {
2949
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2950
				$cidrprefix = 32;
2951
			}
2952
		}
2953
		$iflist = get_configured_interface_list();
2954
		foreach ($iflist as $if => $ifname) {
2955
			if ($ignore_if == $if) {
2956
				continue;
2957
			}
2958

    
2959
			if ($isipv6) {
2960
				$if_ipv6 = get_interface_ipv6($if);
2961
				$if_snbitsv6 = get_interface_subnetv6($if);
2962
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2963
					$where_entry = array();
2964
					$where_entry['if'] = $if;
2965
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2966
					$where_configured[] = $where_entry;
2967
				}
2968
			} else {
2969
				$if_ipv4 = get_interface_ip($if);
2970
				$if_snbitsv4 = get_interface_subnet($if);
2971
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
2972
					$where_entry = array();
2973
					$where_entry['if'] = $if;
2974
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
2975
					$where_configured[] = $where_entry;
2976
				}
2977
			}
2978
		}
2979
	} else {
2980
		if ($isipv6) {
2981
			$interface_list_ips = get_configured_ipv6_addresses();
2982
		} else {
2983
			$interface_list_ips = get_configured_ip_addresses();
2984
		}
2985

    
2986
		foreach ($interface_list_ips as $if => $ilips) {
2987
			if ($ignore_if == $if) {
2988
				continue;
2989
			}
2990
			if (strcasecmp($ipaddr, $ilips) == 0) {
2991
				$where_entry = array();
2992
				$where_entry['if'] = $if;
2993
				$where_entry['ip_or_subnet'] = $ilips;
2994
				$where_configured[] = $where_entry;
2995
			}
2996
		}
2997
	}
2998

    
2999
	if ($check_localip) {
3000
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, text_to_compressed_ip6($config['l2tp']['localip'])) == 0)) {
3001
			$where_entry = array();
3002
			$where_entry['if'] = 'l2tp';
3003
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
3004
			$where_configured[] = $where_entry;
3005
		}
3006
	}
3007

    
3008
	return $where_configured;
3009
}
3010

    
3011
/****f* pfsense-utils/pfSense_handle_custom_code
3012
 * NAME
3013
 *   pfSense_handle_custom_code
3014
 * INPUTS
3015
 *   directory name to process
3016
 * RESULT
3017
 *   globs the directory and includes the files
3018
 */
3019
function pfSense_handle_custom_code($src_dir) {
3020
	// Allow extending of the nat edit page and include custom input validation
3021
	if (is_dir("$src_dir")) {
3022
		$cf = glob($src_dir . "/*.inc");
3023
		foreach ($cf as $nf) {
3024
			if ($nf == "." || $nf == "..") {
3025
				continue;
3026
			}
3027
			// Include the extra handler
3028
			include_once("$nf");
3029
		}
3030
	}
3031
}
3032

    
3033
function set_language() {
3034
	global $config, $g;
3035

    
3036
	if (!empty($config['system']['language'])) {
3037
		$lang = $config['system']['language'];
3038
	} elseif (!empty($g['language'])) {
3039
		$lang = $g['language'];
3040
	}
3041
	$lang .= ".UTF-8";
3042

    
3043
	putenv("LANG={$lang}");
3044
	setlocale(LC_ALL, $lang);
3045
	textdomain("pfSense");
3046
	bindtextdomain("pfSense", "/usr/local/share/locale");
3047
	bind_textdomain_codeset("pfSense", $lang);
3048
}
3049

    
3050
function get_locale_list() {
3051
	$locales = array(
3052
		"bs" => gettext("Bosnian"),
3053
		"zh_CN" => gettext("Chinese"),
3054
		"zh_Hans_CN" => gettext("Chinese (Simplified, China)"),
3055
		"zh_HK" => gettext("Chinese (Hong Kong)"),
3056
		"zh_TW" => gettext("Chinese (Taiwan)"),
3057
		"nl" => gettext("Dutch"),
3058
		"en_US" => gettext("English"),
3059
		"fr" => gettext("French"),
3060
		"de_DE" => gettext("German (Germany)"),
3061
		"nb" => gettext("Norwegian Bokmål"),
3062
		"pl" => gettext("Polish"),
3063
		"pt_PT" => gettext("Portuguese"),
3064
		"pt_BR" => gettext("Portuguese (Brazil)"),
3065
		"ru" => gettext("Russian"),
3066
		"es" => gettext("Spanish"),
3067
		"es_AR" => gettext("Spanish (Argentina)"),
3068
	);
3069

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

    
3074
	//asort($locales);
3075

    
3076
	return $locales;
3077
}
3078

    
3079
function return_hex_ipv4($ipv4) {
3080
	if (!is_ipaddrv4($ipv4)) {
3081
		return(false);
3082
	}
3083

    
3084
	/* we need the hex form of the interface IPv4 address */
3085
	$ip4arr = explode(".", $ipv4);
3086
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
3087
}
3088

    
3089
function convert_ipv6_to_128bit($ipv6) {
3090
	if (!is_ipaddrv6($ipv6)) {
3091
		return(false);
3092
	}
3093

    
3094
	$ip6arr = array();
3095
	$ip6prefix = Net_IPv6::uncompress($ipv6);
3096
	$ip6arr = explode(":", $ip6prefix);
3097
	/* binary presentation of the prefix for all 128 bits. */
3098
	$ip6prefixbin = "";
3099
	foreach ($ip6arr as $element) {
3100
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3101
	}
3102
	return($ip6prefixbin);
3103
}
3104

    
3105
function convert_128bit_to_ipv6($ip6bin) {
3106
	if (strlen($ip6bin) <> 128) {
3107
		return(false);
3108
	}
3109

    
3110
	$ip6arr = array();
3111
	$ip6binarr = array();
3112
	$ip6binarr = str_split($ip6bin, 16);
3113
	foreach ($ip6binarr as $binpart) {
3114
		$ip6arr[] = dechex(bindec($binpart));
3115
	}
3116
	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
3117

    
3118
	return($ip6addr);
3119
}
3120

    
3121

    
3122
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3123
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3124
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3125
/* 6to4 is 16 bits, e.g. 65535 */
3126
function calculate_ipv6_delegation_length($if) {
3127
	global $config;
3128

    
3129
	if (!is_array($config['interfaces'][$if])) {
3130
		return false;
3131
	}
3132

    
3133
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3134
		case "6to4":
3135
			$pdlen = 16;
3136
			break;
3137
		case "6rd":
3138
			$rd6cfg = $config['interfaces'][$if];
3139
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3140
			$pdlen = (64 - ((int) $rd6plen[1] + (32 - (int) $rd6cfg['prefix-6rd-v4plen'])));
3141
			break;
3142
		case "dhcp6":
3143
			$dhcp6cfg = $config['interfaces'][$if];
3144
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3145
			break;
3146
		default:
3147
			$pdlen = 0;
3148
			break;
3149
	}
3150
	return($pdlen);
3151
}
3152

    
3153
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3154
	$prefix = Net_IPv6::uncompress($prefix, true);
3155
	$suffix = Net_IPv6::uncompress($suffix, true);
3156

    
3157
	/*
3158
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3159
	 *                ^^^^ ^
3160
	 *                |||| \-> 64
3161
	 *                |||\---> 63, 62, 61, 60
3162
	 *                ||\----> 56
3163
	 *                |\-----> 52
3164
	 *                \------> 48
3165
	 */
3166

    
3167
	switch ($len) {
3168
	case 48:
3169
		$prefix_len = 15;
3170
		break;
3171
	case 52:
3172
		$prefix_len = 16;
3173
		break;
3174
	case 56:
3175
		$prefix_len = 17;
3176
		break;
3177
	case 59:
3178
	case 60:
3179
		$prefix_len = 18;
3180
		break;
3181
	/*
3182
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
3183
	 * we let user chose this bit it can end up out of PD network
3184
	 *
3185
	 * Leave this with 20 for now until we find a way to let user
3186
	 * chose it. The side-effect is users with PD with one of these
3187
	 * lengths will not be able to setup DHCP server range for full
3188
	 * PD size, only for last /64 network
3189
	 */
3190
	case 63:
3191
	case 62:
3192
	case 61:
3193
	default:
3194
		$prefix_len = 20;
3195
		break;
3196
	}
3197

    
3198
	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
3199
	    substr($suffix, $prefix_len));
3200
}
3201

    
3202
function dhcpv6_pd_str_help($pdlen) {
3203
	$result = '';
3204

    
3205
	switch ($pdlen) {
3206
	case 48:
3207
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
3208
		break;
3209
	case 52:
3210
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
3211
		break;
3212
	case 56:
3213
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
3214
		break;
3215
	case 59:
3216
	case 60:
3217
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
3218
		break;
3219
	/*
3220
	 * XXX 63, 62 and 61 should use same mask as 60 but if
3221
	 * we let the user choose this bit it can end up out of PD network
3222
	 *
3223
	 * Leave this with the same as 64 for now until we find a way to
3224
	 * let the user choose it. The side-effect is users with PD with one
3225
	 * of these lengths will not be able to setup DHCP server ranges
3226
	 * for full PD size, only for last /64 network
3227
	 */
3228
	case 61:
3229
	case 62:
3230
	case 63:
3231
	case 64:
3232
	default:
3233
		$result = '::xxxx:xxxx:xxxx:xxxx';
3234
		break;
3235
	}
3236

    
3237
	return $result;
3238
}
3239

    
3240
function huawei_rssi_to_string($rssi) {
3241
	$dbm = array();
3242
	$i = 0;
3243
	$dbstart = -113;
3244
	while ($i < 32) {
3245
		$dbm[$i] = $dbstart + ($i * 2);
3246
		$i++;
3247
	}
3248
	$percent = round(($rssi / 31) * 100);
3249
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3250
	return $string;
3251
}
3252

    
3253
function huawei_mode_to_string($mode, $submode) {
3254
	$modes[0] = gettext("None");
3255
	$modes[1] = "AMPS";
3256
	$modes[2] = "CDMA";
3257
	$modes[3] = "GSM/GPRS";
3258
	$modes[4] = "HDR";
3259
	$modes[5] = "WCDMA";
3260
	$modes[6] = "GPS";
3261

    
3262
	$submodes[0] = gettext("No Service");
3263
	$submodes[1] = "GSM";
3264
	$submodes[2] = "GPRS";
3265
	$submodes[3] = "EDGE";
3266
	$submodes[4] = "WCDMA";
3267
	$submodes[5] = "HSDPA";
3268
	$submodes[6] = "HSUPA";
3269
	$submodes[7] = "HSDPA+HSUPA";
3270
	$submodes[8] = "TD-SCDMA";
3271
	$submodes[9] = "HSPA+";
3272
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3273
	return $string;
3274
}
3275

    
3276
function huawei_service_to_string($state) {
3277
	$modes[0] = gettext("No Service");
3278
	$modes[1] = gettext("Restricted Service");
3279
	$modes[2] = gettext("Valid Service");
3280
	$modes[3] = gettext("Restricted Regional Service");
3281
	$modes[4] = gettext("Powersaving Service");
3282
	$modes[255] = gettext("Unknown Service");
3283
	$string = $modes[$state];
3284
	return $string;
3285
}
3286

    
3287
function huawei_simstate_to_string($state) {
3288
	$modes[0] = gettext("Invalid SIM/locked State");
3289
	$modes[1] = gettext("Valid SIM State");
3290
	$modes[2] = gettext("Invalid SIM CS State");
3291
	$modes[3] = gettext("Invalid SIM PS State");
3292
	$modes[4] = gettext("Invalid SIM CS/PS State");
3293
	$modes[255] = gettext("Missing SIM State");
3294
	$string = $modes[$state];
3295
	return $string;
3296
}
3297

    
3298
function zte_rssi_to_string($rssi) {
3299
	return huawei_rssi_to_string($rssi);
3300
}
3301

    
3302
function zte_mode_to_string($mode, $submode) {
3303
	$modes[0] = gettext("No Service");
3304
	$modes[1] = gettext("Limited Service");
3305
	$modes[2] = "GPRS";
3306
	$modes[3] = "GSM";
3307
	$modes[4] = "UMTS";
3308
	$modes[5] = "EDGE";
3309
	$modes[6] = "HSDPA";
3310

    
3311
	$submodes[0] = "CS_ONLY";
3312
	$submodes[1] = "PS_ONLY";
3313
	$submodes[2] = "CS_PS";
3314
	$submodes[3] = "CAMPED";
3315
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3316
	return $string;
3317
}
3318

    
3319
function zte_service_to_string($service) {
3320
	$modes[0] = gettext("Initializing Service");
3321
	$modes[1] = gettext("Network Lock error Service");
3322
	$modes[2] = gettext("Network Locked Service");
3323
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3324
	$string = $modes[$service];
3325
	return $string;
3326
}
3327

    
3328
function zte_simstate_to_string($state) {
3329
	$modes[0] = gettext("No action State");
3330
	$modes[1] = gettext("Network lock State");
3331
	$modes[2] = gettext("(U)SIM card lock State");
3332
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3333
	$string = $modes[$state];
3334
	return $string;
3335
}
3336

    
3337
function get_configured_pppoe_server_interfaces() {
3338
	global $config;
3339
	$iflist = array();
3340
	if (is_array($config['pppoes']['pppoe'])) {
3341
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3342
			if ($pppoe['mode'] == "server") {
3343
				$int = "poes". $pppoe['pppoeid'];
3344
				$iflist[$int] = strtoupper($int);
3345
			}
3346
		}
3347
	}
3348
	return $iflist;
3349
}
3350

    
3351
function get_pppoes_child_interfaces($ifpattern) {
3352
	$if_arr = array();
3353
	if ($ifpattern == "") {
3354
		return;
3355
	}
3356

    
3357
	exec("/sbin/ifconfig", $out, $ret);
3358
	foreach ($out as $line) {
3359
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3360
			$if_arr[] = $match[1];
3361
		}
3362
	}
3363
	return $if_arr;
3364

    
3365
}
3366

    
3367
/****f* pfsense-utils/pkg_call_plugins
3368
 * NAME
3369
 *   pkg_call_plugins
3370
 * INPUTS
3371
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3372
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3373
 * RESULT
3374
 *   returns associative array results from the plugin calls for each package
3375
 * NOTES
3376
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3377
 ******/
3378
function pkg_call_plugins($plugin_type, $plugin_params) {
3379
	global $g, $config;
3380
	$results = array();
3381
	if (!is_array($config['installedpackages']['package'])) {
3382
		return $results;
3383
	}
3384
	foreach ($config['installedpackages']['package'] as $package) {
3385
		if (is_array($package['plugins']['item'])) {
3386
			foreach ($package['plugins']['item'] as $plugin) {
3387
				if ($plugin['type'] == $plugin_type) {
3388
					if (file_exists($package['include_file'])) {
3389
						require_once($package['include_file']);
3390
					} else {
3391
						continue;
3392
					}
3393
					$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3394
					$plugin_function = $pkgname . '_'. $plugin_type;
3395
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3396
				}
3397
			}
3398
		}
3399
	}
3400
	return $results;
3401
}
3402

    
3403
// Convert IPv6 addresses to lower case
3404
function addrtolower($ip) {
3405
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3406
		return(strtolower($ip));
3407
	} else {
3408
		return($ip);
3409
	}
3410
}
3411

    
3412
function compare_by_name($a, $b) {
3413
	return strcasecmp($a['name'], $b['name']);
3414
}
3415

    
3416
/****f* pfsense-utils/getarraybyref
3417
 * NAME
3418
 *   getarraybyref
3419
 * INPUTS
3420
 *   $array the array of which a items array needs to be found. 
3421
 *   $args.. the sub-items to be retrieved/created
3422
 * RESULT
3423
 *   returns the array that was retrieved from configuration, its created if it does not exist
3424
 * NOTES
3425
 *   Used by haproxy / acme / others.?. . 
3426
 *   can be used like this:  $a_certificates = getarraybyref($config, 'installedpackages', 'acme', 'certificates', 'item');
3427
 ******/
3428
function &getarraybyref(&$array) {
3429
	if (!isset($array)) {
3430
		return false;
3431
	}
3432
	if (!is_array($array)) {
3433
		$array = array();
3434
	}
3435
	$item = &$array;
3436
	$arg = func_get_args();
3437
	for($i = 1; $i < count($arg); $i++) {
3438
		$itemindex = $arg[$i];
3439
		if (!is_array($item[$itemindex])) {
3440
			$item[$itemindex] = array();
3441
		}
3442
		$item = &$item[$itemindex];
3443
	}
3444
	return $item;
3445
}
3446

    
3447
?>
(38-38/60)