Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
219
	$csslist = get_css_files();
220

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
772
	return "";
773
}
774

    
775
/*
776
 * Return true if the CARP status of at least one interface of a captive portal zone is in backup mode
777
 * This function return false if CARP is not enabled on any interface of the captive portal zone
778
 */
779
function captiveportal_ha_is_node_in_backup_mode($cpzone) {
780
	global $config;
781

    
782
	$cpinterfaces = explode(",", $config['captiveportal'][$cpzone]['interface']);
783

    
784
	if (is_array($config['virtualip']['vip'])) {
785
		foreach ($cpinterfaces as $interface) {
786
			foreach ($config['virtualip']['vip'] as $vip) {
787
				if (($vip['interface'] == $interface) && ($vip['mode'] == "carp")) {
788
					if (get_carp_interface_status("_vip{$vip['uniqid']}") != "MASTER") {
789
						return true;
790
					}
791
				}
792
			}
793
		}
794
	}
795
	return false;
796
}
797

    
798
/*
799
 * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
800
 */
801
function get_pfsync_interface_status($pfsyncinterface) {
802
	if (!does_interface_exist($pfsyncinterface)) {
803
		return;
804
	}
805

    
806
	return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
807
}
808

    
809
/*
810
 * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
811
 */
812
function add_rule_to_anchor($anchor, $rule, $label) {
813
	mwexec("echo " . escapeshellarg($rule) . " | /sbin/pfctl -a " . escapeshellarg($anchor) . ":" . escapeshellarg($label) . " -f -");
814
}
815

    
816
/*
817
 * remove_text_from_file
818
 * remove $text from file $file
819
 */
820
function remove_text_from_file($file, $text) {
821
	if (!file_exists($file) && !is_writable($file)) {
822
		return;
823
	}
824
	$filecontents = file_get_contents($file);
825
	$text = str_replace($text, "", $filecontents);
826
	@file_put_contents($file, $text);
827
}
828

    
829
/*
830
 *   after_sync_bump_adv_skew(): create skew values by 1S
831
 */
832
function after_sync_bump_adv_skew() {
833
	global $config, $g;
834
	$processed_skew = 1;
835
	init_config_arr(array('virtualip', 'vip'));
836
	$a_vip = &$config['virtualip']['vip'];
837
	foreach ($a_vip as $vipent) {
838
		if ($vipent['advskew'] <> "") {
839
			$processed_skew = 1;
840
			$vipent['advskew'] = $vipent['advskew']+1;
841
		}
842
	}
843
	if ($processed_skew == 1) {
844
		write_config(gettext("After synch increase advertising skew"));
845
	}
846
}
847

    
848
/*
849
 * get_filename_from_url($url): converts a url to its filename.
850
 */
851
function get_filename_from_url($url) {
852
	return basename($url);
853
}
854

    
855
/*
856
 *   get_dir: return an array of $dir
857
 */
858
function get_dir($dir) {
859
	$dir_array = array();
860
	$d = dir($dir);
861
	if (!is_object($d)) {
862
		return array();
863
	}
864
	while (false !== ($entry = $d->read())) {
865
		array_push($dir_array, $entry);
866
	}
867
	$d->close();
868
	return $dir_array;
869
}
870

    
871
/****f* pfsense-utils/WakeOnLan
872
 * NAME
873
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
874
 * RESULT
875
 *   true/false - true if the operation was successful
876
 ******/
877
function WakeOnLan($addr, $mac) {
878
	$addr_byte = explode(':', $mac);
879
	$hw_addr = '';
880

    
881
	for ($a = 0; $a < 6; $a++) {
882
		$hw_addr .= chr(hexdec($addr_byte[$a]));
883
	}
884

    
885
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
886

    
887
	for ($a = 1; $a <= 16; $a++) {
888
		$msg .= $hw_addr;
889
	}
890

    
891
	// send it to the broadcast address using UDP
892
	$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
893
	if ($s == false) {
894
		log_error(gettext("Error creating socket!"));
895
		log_error(sprintf(gettext("Error code is '%1\$s' - %2\$s"), socket_last_error($s), socket_strerror(socket_last_error($s))));
896
	} else {
897
		// setting a broadcast option to socket:
898
		$opt_ret = socket_set_option($s, 1, 6, TRUE);
899
		if ($opt_ret < 0) {
900
			log_error(sprintf(gettext("setsockopt() failed, error: %s"), strerror($opt_ret)));
901
		}
902
		$e = socket_sendto($s, $msg, strlen($msg), 0, $addr, 2050);
903
		socket_close($s);
904
		log_error(sprintf(gettext('Magic Packet sent (%1$s) to (%2$s) MAC=%3$s'), $e, $addr, $mac));
905
		return true;
906
	}
907

    
908
	return false;
909
}
910

    
911
/*
912
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
913
 *					 Useful for finding paths and stripping file extensions.
914
 */
915
function reverse_strrchr($haystack, $needle) {
916
	if (!is_string($haystack)) {
917
		return;
918
	}
919
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
920
}
921

    
922
/*
923
 *  backup_config_section($section): returns as an xml file string of
924
 *                                   the configuration section
925
 */
926
function backup_config_section($section_name) {
927
	global $config;
928
	$new_section = &$config[$section_name];
929
	/* generate configuration XML */
930
	$xmlconfig = dump_xml_config($new_section, $section_name);
931
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
932
	return $xmlconfig;
933
}
934

    
935
/*
936
 *  restore_config_section($section_name, new_contents): restore a configuration section,
937
 *                                                  and write the configuration out
938
 *                                                  to disk/cf.
939
 */
940
function restore_config_section($section_name, $new_contents) {
941
	global $config, $g;
942
	$fout = fopen("{$g['tmp_path']}/tmpxml", "w");
943
	fwrite($fout, $new_contents);
944
	fclose($fout);
945

    
946
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
947
	if ($xml['pfsense']) {
948
		$xml = $xml['pfsense'];
949
	}
950
	else if ($xml['m0n0wall']) {
951
		$xml = $xml['m0n0wall'];
952
	}
953
	if ($xml[$section_name]) {
954
		$section_xml = $xml[$section_name];
955
	} else {
956
		$section_xml = -1;
957
	}
958

    
959
	@unlink($g['tmp_path'] . "/tmpxml");
960
	if ($section_xml === -1) {
961
		return false;
962
	}
963

    
964
	/* Save current pkg repo to re-add on new config */
965
	unset($pkg_repo_conf_path);
966
	if ($section_name == "system" &&
967
	    isset($config['system']['pkg_repo_conf_path'])) {
968
		$pkg_repo_conf_path = $config['system']['pkg_repo_conf_path'];
969
	}
970

    
971
	$config[$section_name] = &$section_xml;
972
	if (file_exists("{$g['tmp_path']}/config.cache")) {
973
		unlink("{$g['tmp_path']}/config.cache");
974
	}
975

    
976
	/* Restore previously pkg repo configured */
977
	if ($section_name == "system") {
978
		if (isset($pkg_repo_conf_path)) {
979
			$config['system']['pkg_repo_conf_path'] =
980
			    $pkg_repo_conf_path;
981
		} elseif (isset($config['system']['pkg_repo_conf_path'])) {
982
			unset($config['system']['pkg_repo_conf_path']);
983
		}
984
	}
985

    
986
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
987
	disable_security_checks();
988
	return true;
989
}
990

    
991
/*
992
 *  merge_config_section($section_name, new_contents):   restore a configuration section,
993
 *                                                  and write the configuration out
994
 *                                                  to disk/cf.  But preserve the prior
995
 * 													structure if needed
996
 */
997
function merge_config_section($section_name, $new_contents) {
998
	global $config;
999
	$fname = get_tmp_filename();
1000
	$fout = fopen($fname, "w");
1001
	fwrite($fout, $new_contents);
1002
	fclose($fout);
1003
	$section_xml = parse_xml_config($fname, $section_name);
1004
	$config[$section_name] = $section_xml;
1005
	unlink($fname);
1006
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
1007
	disable_security_checks();
1008
	return;
1009
}
1010

    
1011
/*
1012
 * rmdir_recursive($path, $follow_links=false)
1013
 * Recursively remove a directory tree (rm -rf path)
1014
 * This is for directories _only_
1015
 */
1016
function rmdir_recursive($path, $follow_links=false) {
1017
	$to_do = glob($path);
1018
	if (!is_array($to_do)) {
1019
		$to_do = array($to_do);
1020
	}
1021
	foreach ($to_do as $workingdir) { // Handle wildcards by foreaching.
1022
		if (file_exists($workingdir)) {
1023
			if (is_dir($workingdir)) {
1024
				$dir = opendir($workingdir);
1025
				while ($entry = readdir($dir)) {
1026
					if (is_file("$workingdir/$entry") || ((!$follow_links) && is_link("$workingdir/$entry"))) {
1027
						unlink("$workingdir/$entry");
1028
					} elseif (is_dir("$workingdir/$entry") && $entry != '.' && $entry != '..') {
1029
						rmdir_recursive("$workingdir/$entry");
1030
					}
1031
				}
1032
				closedir($dir);
1033
				rmdir($workingdir);
1034
			} elseif (is_file($workingdir)) {
1035
				unlink($workingdir);
1036
			}
1037
		}
1038
	}
1039
	return;
1040
}
1041

    
1042
/*
1043
 * host_firmware_version(): Return the versions used in this install
1044
 */
1045
function host_firmware_version($tocheck = "") {
1046
	global $g, $config;
1047

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

    
1050
	return array(
1051
		"firmware" => array("version" => $g['product_version']),
1052
		"kernel"   => array("version" => $os_version),
1053
		"base"     => array("version" => $os_version),
1054
		"platform" => $g['platform'],
1055
		"config_version" => $config['version']
1056
	);
1057
}
1058

    
1059
function get_disk_info() {
1060
	$diskout = "";
1061
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
1062
	return explode(' ', $diskout[0]);
1063
}
1064

    
1065
/****f* pfsense-utils/strncpy
1066
 * NAME
1067
 *   strncpy - copy strings
1068
 * INPUTS
1069
 *   &$dst, $src, $length
1070
 * RESULT
1071
 *   none
1072
 ******/
1073
function strncpy(&$dst, $src, $length) {
1074
	if (strlen($src) > $length) {
1075
		$dst = substr($src, 0, $length);
1076
	} else {
1077
		$dst = $src;
1078
	}
1079
}
1080

    
1081
/****f* pfsense-utils/reload_interfaces_sync
1082
 * NAME
1083
 *   reload_interfaces - reload all interfaces
1084
 * INPUTS
1085
 *   none
1086
 * RESULT
1087
 *   none
1088
 ******/
1089
function reload_interfaces_sync() {
1090
	global $config, $g;
1091

    
1092
	if ($g['debug']) {
1093
		log_error(gettext("reload_interfaces_sync() is starting."));
1094
	}
1095

    
1096
	/* parse config.xml again */
1097
	$config = parse_config(true);
1098

    
1099
	/* enable routing */
1100
	system_routing_enable();
1101
	if ($g['debug']) {
1102
		log_error(gettext("Enabling system routing"));
1103
	}
1104

    
1105
	if ($g['debug']) {
1106
		log_error(gettext("Cleaning up Interfaces"));
1107
	}
1108

    
1109
	/* set up interfaces */
1110
	interfaces_configure();
1111
}
1112

    
1113
/****f* pfsense-utils/reload_all
1114
 * NAME
1115
 *   reload_all - triggers a reload of all settings
1116
 *   * INPUTS
1117
 *   none
1118
 * RESULT
1119
 *   none
1120
 ******/
1121
function reload_all() {
1122
	send_event("service reload all");
1123
}
1124

    
1125
/****f* pfsense-utils/reload_interfaces
1126
 * NAME
1127
 *   reload_interfaces - triggers a reload of all interfaces
1128
 * INPUTS
1129
 *   none
1130
 * RESULT
1131
 *   none
1132
 ******/
1133
function reload_interfaces() {
1134
	send_event("interface all reload");
1135
}
1136

    
1137
/****f* pfsense-utils/reload_all_sync
1138
 * NAME
1139
 *   reload_all - reload all settings
1140
 *   * INPUTS
1141
 *   none
1142
 * RESULT
1143
 *   none
1144
 ******/
1145
function reload_all_sync() {
1146
	global $config, $g;
1147

    
1148
	/* parse config.xml again */
1149
	$config = parse_config(true);
1150

    
1151
	/* set up our timezone */
1152
	system_timezone_configure();
1153

    
1154
	/* set up our hostname */
1155
	system_hostname_configure();
1156

    
1157
	/* make hosts file */
1158
	system_hosts_generate();
1159

    
1160
	/* generate resolv.conf */
1161
	system_resolvconf_generate();
1162

    
1163
	/* enable routing */
1164
	system_routing_enable();
1165

    
1166
	/* set up interfaces */
1167
	interfaces_configure();
1168

    
1169
	/* start dyndns service */
1170
	services_dyndns_configure();
1171

    
1172
	/* configure cron service */
1173
	configure_cron();
1174

    
1175
	/* start the NTP client */
1176
	system_ntp_configure();
1177

    
1178
	/* sync pw database */
1179
	unlink_if_exists("/etc/spwd.db.tmp");
1180
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
1181

    
1182
	/* restart sshd */
1183
	send_event("service restart sshd");
1184

    
1185
	/* restart webConfigurator if needed */
1186
	send_event("service restart webgui");
1187
}
1188

    
1189
function load_loader_conf($loader_conf = NULL, $local = false) {
1190

    
1191
	if ($loader_conf == NULL) {
1192
		return (NULL);
1193
	}
1194
	if (file_exists($loader_conf)) {
1195
		$input = file_get_contents($loader_conf);
1196
	} else {
1197
		$input = "";
1198
	}
1199

    
1200
	$input_split = explode("\n", $input);
1201

    
1202
	/*
1203
	 * Loop through and only add lines that are not empty and not
1204
	 * managed by us.
1205
	 */
1206
	$data = array();
1207
	/* These values should be removed from loader.conf and loader.conf.local
1208
	 * As they will be replaced when necessary. */
1209
	$remove = array("hw.usb.no_pf", "hint.mdio.0.at", "hint.e6000sw.0",
1210
	    "hw.e6000sw.default_disabled", "vm.pmap.pti",
1211
	    "net.pf.request_maxcount");
1212
	if (!$local) {
1213
		/* These values should only be filtered in loader.conf, not .local */
1214
		$remove = array_merge($remove,
1215
		    array("autoboot_delay", "console", "comconsole_speed",
1216
		    "boot_multicons", "boot_serial", "hint.uart.0.flags",
1217
		    "hint.uart.1.flags"));
1218
	}
1219
	foreach ($input_split as $line) {
1220
		if (empty($line)) {
1221
			continue;
1222
		}
1223
		$skip = false;
1224
		list($name, $value) = explode('=', $line, 2);
1225
		foreach($remove as $rid => $rkey) {
1226
			if (strncasecmp(trim($name), $rkey, strlen($rkey)) == 0) {
1227
				$skip = true;
1228
				break;
1229
			}
1230
		}
1231
		if (!$skip) {
1232
			$data[] = $line;
1233
		}
1234
	}
1235

    
1236
	return ($data);
1237
}
1238

    
1239
function setup_loader_settings($path = "", $upgrade = false) {
1240
	global $g, $config;
1241

    
1242
	$boot_config_file = "{$path}/boot.config";
1243
	$loader_conf_file = "{$path}/boot/loader.conf";
1244

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

    
1247
	$vga_only = false;
1248
	$serial_only = false;
1249
	$specific_platform = system_identify_specific_platform();
1250
	$video_console_type = (get_single_sysctl("machdep.bootmethod") == "UEFI") ? "efi" : "vidconsole";
1251
	if ($specific_platform['name'] == 'XG-1540') {
1252
		$vga_only = true;
1253
	} elseif ($specific_platform['name'] == 'Turbot Dual-E') {
1254
		$g['primaryconsole_force'] = "video";
1255
	} elseif ($specific_platform['name'] == 'RCC-VE' ||
1256
	    $specific_platform['name'] == 'RCC' ||
1257
	    $specific_platform['name'] == 'SG-2220' ||
1258
	    $specific_platform['name'] == 'apu2') {
1259
		$serial_only = true;
1260
	}
1261

    
1262
	/* Serial console - write out /boot.config */
1263
	if (file_exists($boot_config_file)) {
1264
		$boot_config = file_get_contents($boot_config_file);
1265
	} else {
1266
		$boot_config = "";
1267
	}
1268
	$boot_config_split = explode("\n", $boot_config);
1269
	$data = array();
1270
	foreach ($boot_config_split as $bcs) {
1271
		/* Ignore -D and -h lines now */
1272
		if (!empty($bcs) && !stristr($bcs, "-D") &&
1273
		    !stristr($bcs, "-h")) {
1274
			$data[] = $bcs;
1275
		}
1276
	}
1277
	if ($serial_only === true) {
1278
		$data[] = "-S{$serialspeed} -h";
1279
	} elseif (is_serial_enabled()) {
1280
		$data[] = "-S{$serialspeed} -D";
1281
	}
1282

    
1283
	if (empty($data)) {
1284
		@unlink($boot_conf_file);
1285
	} else {
1286
		safe_write_file($boot_config_file, $data);
1287
	}
1288
	unset($data, $boot_config, $boot_config_file, $boot_config_split);
1289

    
1290
	/* Serial console - write out /boot/loader.conf */
1291
	if ($upgrade) {
1292
		system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1293
	}
1294

    
1295
	$data = load_loader_conf($loader_conf_file, false);
1296
	if ($serial_only === true) {
1297
		$data[] = 'boot_serial="YES"';
1298
		$data[] = 'console="comconsole"';
1299
		$data[] = 'comconsole_speed="' . $serialspeed . '"';
1300
	} elseif ($vga_only === true) {
1301
		$data[] = "console=\"{$video_console_type}\"";
1302
	} elseif (is_serial_enabled()) {
1303
		$data[] = 'boot_multicons="YES"';
1304
		$data[] = 'boot_serial="YES"';
1305
		$primaryconsole = isset($g['primaryconsole_force']) ?
1306
		    $g['primaryconsole_force'] :
1307
		    $config['system']['primaryconsole'];
1308
		switch ($primaryconsole) {
1309
			case "video":
1310
				$data[] = "console=\"{$video_console_type},comconsole\"";
1311
				break;
1312
			case "serial":
1313
			default:
1314
				$data[] = "console=\"comconsole,{$video_console_type}\"";
1315
		}
1316
		$data[] = 'comconsole_speed="' . $serialspeed . '"';
1317
	}
1318

    
1319
	if ($specific_platform['name'] == 'RCC-VE' ||
1320
	    $specific_platform['name'] == 'RCC' ||
1321
	    $specific_platform['name'] == 'SG-2220') {
1322
		$data[] = 'comconsole_port="0x2F8"';
1323
		$data[] = 'hint.uart.0.flags="0x00"';
1324
		$data[] = 'hint.uart.1.flags="0x10"';
1325
	}
1326
	$data[] = 'autoboot_delay="3"';
1327
	$data[] = 'hw.usb.no_pf="1"';
1328
	if (isset($config['system']['pti_disabled'])) {
1329
		$data[] = 'vm.pmap.pti="0"';
1330
	}
1331

    
1332
	if (isset($config['system']['maximumtableentries'])) {
1333
		$maximumtableentries = $config['system']['maximumtableentries'];
1334
	} else {
1335
		$maximumtableentries = pfsense_default_table_entries_size();
1336
	}
1337
	$data[] = 'net.pf.request_maxcount="' .  $maximumtableentries . '"';
1338

    
1339
	/* Enable ALTQ support for hnX NICs. */
1340
	$data[] = 'hw.hn.vf_transparent=0';
1341
	$data[] = 'hw.hn.use_if_start=1';
1342

    
1343
	safe_write_file($loader_conf_file, $data);
1344

    
1345
	/* Filter loader.conf.local to avoid duplicate settings. */
1346
	$loader_conf_file = "{$path}/boot/loader.conf.local";
1347
	$data = load_loader_conf($loader_conf_file, true);
1348
	if (empty($data)) {
1349
		@unlink($loader_conf_file);
1350
	} else {
1351
		safe_write_file($loader_conf_file, $data);
1352
	}
1353

    
1354
}
1355

    
1356
function console_configure($when = "save", $path = "") {
1357
	global $config;
1358
	$ttys_file = "{$path}/etc/ttys";
1359

    
1360
	/* Update the loader settings. */
1361
	setup_loader_settings($path, ($when == "upgrade"));
1362

    
1363
	$ttys = file_get_contents($ttys_file);
1364
	$ttys_split = explode("\n", $ttys);
1365

    
1366
	$data = array();
1367

    
1368
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1369

    
1370
	if (isset($config['system']['disableconsolemenu'])) {
1371
		$console_type = 'Pc';
1372
		$serial_type = '3wire';
1373
	} else {
1374
		$console_type = 'al.Pc';
1375
		$serial_type = 'al.3wire';
1376
	}
1377

    
1378
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1379
	$ttyv0_line =
1380
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\txterm\tonifexists secure";
1381
	$ttyu_line =
1382
	    "\"/usr/libexec/getty {$serial_type}\"\tvt100\t{$on_off}\tsecure";
1383

    
1384
	$found = array();
1385

    
1386
	foreach ($ttys_split as $tty) {
1387
		/* Ignore blank lines */
1388
		if (empty($tty)) {
1389
			continue;
1390
		}
1391

    
1392
		if (stristr($tty, "ttyv0")) {
1393
			$found['ttyv0'] = 1;
1394
			$data[] = $ttyv0_line;
1395
		} elseif (stristr($tty, "ttyu")) {
1396
			$ttyn = substr($tty, 0, 5);
1397
			$found[$ttyn] = 1;
1398
			$data[] = "{$ttyn}\t{$ttyu_line}";
1399
		} elseif (substr($tty, 0, 7) == 'console') {
1400
			$found['console'] = 1;
1401
			$data[] = $tty;
1402
		} else {
1403
			$data[] = $tty;
1404
		}
1405
	}
1406
	unset($on_off, $console_type, $serial_type);
1407

    
1408
	/* Detect missing main lines on original file and try to rebuild it */
1409
	$items = array(
1410
		'console',
1411
		'ttyv0',
1412
		'ttyu0',
1413
		'ttyu1',
1414
		'ttyu2',
1415
		'ttyu3'
1416
	);
1417

    
1418
	foreach ($items as $item) {
1419
		if (isset($found[$item])) {
1420
			continue;
1421
		}
1422

    
1423
		if ($item == 'console') {
1424
			$data[] = $console_line;
1425
		} elseif ($item == 'ttyv0') {
1426
			$data[] = $ttyv0_line;
1427
		} else {
1428
			$data[] = "{$item}\t{$ttyu_line}";
1429
		}
1430
	}
1431

    
1432
	safe_write_file($ttys_file, $data);
1433

    
1434
	unset($ttys, $ttys_file, $ttys_split, $data);
1435

    
1436
	if ($when != "upgrade") {
1437
		reload_ttys();
1438
	}
1439

    
1440
	return;
1441
}
1442

    
1443
function is_serial_enabled() {
1444
	global $g, $config;
1445

    
1446
	if (!isset($g['enableserial_force']) &&
1447
	    !isset($config['system']['enableserial'])) {
1448
		return false;
1449
	}
1450

    
1451
	return true;
1452
}
1453

    
1454
function reload_ttys() {
1455
	// Send a HUP signal to init will make it reload /etc/ttys
1456
	posix_kill(1, SIGHUP);
1457
}
1458

    
1459
function print_value_list($list, $count = 10, $separator = ",") {
1460
	$list = implode($separator, array_slice($list, 0, $count));
1461
	if (count($list) < $count) {
1462
		$list .= ".";
1463
	} else {
1464
		$list .= "...";
1465
	}
1466
	return $list;
1467
}
1468

    
1469
/* DHCP enabled on any interfaces? */
1470
function is_dhcp_server_enabled() {
1471
	global $config;
1472

    
1473
	if (!is_array($config['dhcpd'])) {
1474
		return false;
1475
	}
1476

    
1477
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1478
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1479
			return true;
1480
		}
1481
	}
1482

    
1483
	return false;
1484
}
1485

    
1486
/* DHCP enabled on any interfaces? */
1487
function is_dhcpv6_server_enabled() {
1488
	global $config;
1489

    
1490
	if (is_array($config['interfaces'])) {
1491
		foreach ($config['interfaces'] as $ifcfg) {
1492
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1493
				return true;
1494
			}
1495
		}
1496
	}
1497

    
1498
	if (!is_array($config['dhcpdv6'])) {
1499
		return false;
1500
	}
1501

    
1502
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1503
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1504
			return true;
1505
		}
1506
	}
1507

    
1508
	return false;
1509
}
1510

    
1511
/* radvd enabled on any interfaces? */
1512
function is_radvd_enabled() {
1513
	global $config;
1514

    
1515
	if (!is_array($config['dhcpdv6'])) {
1516
		$config['dhcpdv6'] = array();
1517
	}
1518

    
1519
	$dhcpdv6cfg = $config['dhcpdv6'];
1520
	$Iflist = get_configured_interface_list();
1521

    
1522
	/* handle manually configured DHCP6 server settings first */
1523
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1524
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1525
			continue;
1526
		}
1527

    
1528
		if (!isset($dhcpv6ifconf['ramode'])) {
1529
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1530
		}
1531

    
1532
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1533
			continue;
1534
		}
1535

    
1536
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1537
		if (!is_ipaddrv6($ifcfgipv6)) {
1538
			continue;
1539
		}
1540

    
1541
		return true;
1542
	}
1543

    
1544
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1545
	foreach ($Iflist as $if => $ifdescr) {
1546
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1547
			continue;
1548
		}
1549
		if (!isset($config['interfaces'][$if]['enable'])) {
1550
			continue;
1551
		}
1552

    
1553
		$ifcfgipv6 = get_interface_ipv6($if);
1554
		if (!is_ipaddrv6($ifcfgipv6)) {
1555
			continue;
1556
		}
1557

    
1558
		$ifcfgsnv6 = get_interface_subnetv6($if);
1559
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1560

    
1561
		if (!is_ipaddrv6($subnetv6)) {
1562
			continue;
1563
		}
1564

    
1565
		return true;
1566
	}
1567

    
1568
	return false;
1569
}
1570

    
1571
/* Any PPPoE servers enabled? */
1572
function is_pppoe_server_enabled() {
1573
	global $config;
1574

    
1575
	$pppoeenable = false;
1576

    
1577
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1578
		return false;
1579
	}
1580

    
1581
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1582
		if ($pppoes['mode'] == 'server') {
1583
			$pppoeenable = true;
1584
		}
1585
	}
1586

    
1587
	return $pppoeenable;
1588
}
1589

    
1590
/* Optional arg forces hh:mm:ss without days */
1591
function convert_seconds_to_dhms($sec, $showhoursonly = false) {
1592
	if (!is_numericint($sec)) {
1593
		return '-';
1594
	}
1595
	// FIXME: When we move to PHP 7 we can use "intdiv($sec % X, Y)" etc
1596
	list($d, $h, $m, $s) = array(	(int)($showhoursonly ? 0 : $sec/86400),
1597
					(int)(($showhoursonly ? $sec : $sec % 86400)/3600),
1598
					(int)(($sec % 3600)/60),
1599
					$sec % 60
1600
				);
1601
	return ($d > 0 ? $d . 'd ' : '') . sprintf('%02d:%02d:%02d', $h, $m, $s);
1602
}
1603

    
1604
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1605

    
1606
function get_ppp_uptime($port) {
1607
	if (file_exists("/conf/{$port}.log")) {
1608
		$saved_time = file_get_contents("/conf/{$port}.log");
1609
		$uptime_data = explode("\n", $saved_time);
1610
		$sec = 0;
1611
		foreach ($uptime_data as $upt) {
1612
			$sec += substr($upt, 1 + strpos($upt, " "));
1613
		}
1614
		return convert_seconds_to_dhms($sec);
1615
	} else {
1616
		$total_time = gettext("No history data found!");
1617
		return $total_time;
1618
	}
1619
}
1620

    
1621
//returns interface information
1622
function get_interface_info($ifdescr) {
1623
	global $config, $g;
1624

    
1625
	$ifinfo = array();
1626
	if (empty($config['interfaces'][$ifdescr])) {
1627
		return;
1628
	}
1629
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1630
	$ifinfo['enable'] = isset($config['interfaces'][$ifdescr]['enable']);
1631
	$ifinfo['if'] = get_real_interface($ifdescr);
1632

    
1633
	$chkif = $ifinfo['if'];
1634
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1635
	$ifinfo['status'] = $ifinfotmp['status'];
1636
	if (empty($ifinfo['status'])) {
1637
		$ifinfo['status'] = "down";
1638
	}
1639
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1640
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1641
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1642
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1643
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1644
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1645
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1646
	if (isset($ifinfotmp['link0'])) {
1647
		$link0 = "down";
1648
	}
1649
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1650
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1651
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1652
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1653
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1654
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1655

    
1656
	/* Use pfctl for non wrapping 64 bit counters */
1657
	/* Pass */
1658
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1659
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1660
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1661
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1662
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1663
	$in4_pass = $pf_in4_pass[5];
1664
	$out4_pass = $pf_out4_pass[5];
1665
	$in4_pass_packets = $pf_in4_pass[3];
1666
	$out4_pass_packets = $pf_out4_pass[3];
1667
	$in6_pass = $pf_in6_pass[5];
1668
	$out6_pass = $pf_out6_pass[5];
1669
	$in6_pass_packets = $pf_in6_pass[3];
1670
	$out6_pass_packets = $pf_out6_pass[3];
1671
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1672
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1673
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1674
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1675

    
1676
	/* Block */
1677
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1678
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1679
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1680
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1681
	$in4_block = $pf_in4_block[5];
1682
	$out4_block = $pf_out4_block[5];
1683
	$in4_block_packets = $pf_in4_block[3];
1684
	$out4_block_packets = $pf_out4_block[3];
1685
	$in6_block = $pf_in6_block[5];
1686
	$out6_block = $pf_out6_block[5];
1687
	$in6_block_packets = $pf_in6_block[3];
1688
	$out6_block_packets = $pf_out6_block[3];
1689
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1690
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1691
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1692
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1693

    
1694
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1695
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1696
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1697
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1698

    
1699
	$ifconfiginfo = "";
1700
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1701
	switch ($link_type) {
1702
		/* DHCP? -> see if dhclient is up */
1703
		case "dhcp":
1704
			/* see if dhclient is up */
1705
			if (find_dhclient_process($ifinfo['if']) != 0) {
1706
				$ifinfo['dhcplink'] = "up";
1707
			} else {
1708
				$ifinfo['dhcplink'] = "down";
1709
			}
1710

    
1711
			break;
1712
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1713
		case "pppoe":
1714
		case "pptp":
1715
		case "l2tp":
1716
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1717
				/* get PPPoE link status for dial on demand */
1718
				$ifinfo["{$link_type}link"] = "up";
1719
			} else {
1720
				$ifinfo["{$link_type}link"] = "down";
1721
			}
1722

    
1723
			break;
1724
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1725
		case "ppp":
1726
			if ($ifinfo['status'] == "up") {
1727
				$ifinfo['ppplink'] = "up";
1728
			} else {
1729
				$ifinfo['ppplink'] = "down" ;
1730
			}
1731

    
1732
			if (empty($ifinfo['status'])) {
1733
				$ifinfo['status'] = "down";
1734
			}
1735

    
1736
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1737
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1738
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1739
						break;
1740
					}
1741
				}
1742
			}
1743
			$dev = $ppp['ports'];
1744
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1745
				break;
1746
			}
1747
			if (!file_exists($dev)) {
1748
				$ifinfo['nodevice'] = 1;
1749
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1750
			}
1751

    
1752
			$usbmodemoutput = array();
1753
			exec("/usr/sbin/usbconfig", $usbmodemoutput);
1754
			$mondev = "{$g['tmp_path']}/3gstats.{$ifdescr}";
1755
			if (file_exists($mondev)) {
1756
				$cellstats = file($mondev);
1757
				/* skip header */
1758
				$a_cellstats = explode(",", $cellstats[1]);
1759
				if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1760
					$ifinfo['cell_rssi'] = huawei_rssi_to_string($a_cellstats[1]);
1761
					$ifinfo['cell_mode'] = huawei_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1762
					$ifinfo['cell_simstate'] = huawei_simstate_to_string($a_cellstats[10]);
1763
					$ifinfo['cell_service'] = huawei_service_to_string(trim($a_cellstats[11]));
1764
				}
1765
				if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1766
					$ifinfo['cell_rssi'] = zte_rssi_to_string($a_cellstats[1]);
1767
					$ifinfo['cell_mode'] = zte_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1768
					$ifinfo['cell_simstate'] = zte_simstate_to_string($a_cellstats[10]);
1769
					$ifinfo['cell_service'] = zte_service_to_string(trim($a_cellstats[11]));
1770
				}
1771
				$ifinfo['cell_upstream'] = $a_cellstats[4];
1772
				$ifinfo['cell_downstream'] = trim($a_cellstats[5]);
1773
				$ifinfo['cell_sent'] = $a_cellstats[6];
1774
				$ifinfo['cell_received'] = trim($a_cellstats[7]);
1775
				$ifinfo['cell_bwupstream'] = $a_cellstats[8];
1776
				$ifinfo['cell_bwdownstream'] = trim($a_cellstats[9]);
1777
			}
1778
			// Calculate cumulative uptime for PPP link. Useful for connections that have per minute/hour contracts so you don't go over!
1779
			if (isset($ppp['uptime'])) {
1780
				$ifinfo['ppp_uptime_accumulated'] = "(".get_ppp_uptime($ifinfo['if']).")";
1781
			}
1782
			break;
1783
		default:
1784
			break;
1785
	}
1786

    
1787
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1788
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1789
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1790
	}
1791

    
1792
	if ($ifinfo['status'] == "up") {
1793
		/* try to determine media with ifconfig */
1794
		unset($ifconfiginfo);
1795
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1796
		$wifconfiginfo = array();
1797
		if (is_interface_wireless($ifdescr)) {
1798
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1799
			array_shift($wifconfiginfo);
1800
		}
1801
		$matches = "";
1802
		foreach ($ifconfiginfo as $ici) {
1803

    
1804
			/* don't list media/speed for wireless cards, as it always
1805
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1806
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1807
				$ifinfo['media'] = $matches[1];
1808
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1809
				$ifinfo['media'] = $matches[1];
1810
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1811
				$ifinfo['media'] = $matches[1];
1812
			}
1813

    
1814
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1815
				if ($matches[1] != "active") {
1816
					$ifinfo['status'] = $matches[1];
1817
				}
1818
				if ($ifinfo['status'] == gettext("running")) {
1819
					$ifinfo['status'] = gettext("up");
1820
				}
1821
			}
1822
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1823
				$ifinfo['channel'] = $matches[1];
1824
			}
1825
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1826
				if ($matches[1][0] == '"') {
1827
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1828
				}
1829
				else {
1830
					$ifinfo['ssid'] = $matches[1];
1831
				}
1832
			}
1833
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1834
				$ifinfo['laggproto'] = $matches[1];
1835
			}
1836
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1837
				$ifinfo['laggport'][] = $matches[1];
1838
			}
1839
		}
1840
		foreach ($wifconfiginfo as $ici) {
1841
			$elements = preg_split("/[ ]+/i", $ici);
1842
			if ($elements[0] != "") {
1843
				$ifinfo['bssid'] = $elements[0];
1844
			}
1845
			if ($elements[3] != "") {
1846
				$ifinfo['rate'] = $elements[3];
1847
			}
1848
			if ($elements[4] != "") {
1849
				$ifinfo['rssi'] = $elements[4];
1850
			}
1851
		}
1852
		/* lookup the gateway */
1853
		if (interface_has_gateway($ifdescr)) {
1854
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1855
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1856
		}
1857
	}
1858

    
1859
	$bridge = "";
1860
	$bridge = link_interface_to_bridge($ifdescr);
1861
	if ($bridge) {
1862
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1863
		if (stristr($bridge_text, "blocking") <> false) {
1864
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1865
			$ifinfo['bridgeint'] = $bridge;
1866
		} else if (stristr($bridge_text, "learning") <> false) {
1867
			$ifinfo['bridge'] = gettext("learning");
1868
			$ifinfo['bridgeint'] = $bridge;
1869
		} else if (stristr($bridge_text, "forwarding") <> false) {
1870
			$ifinfo['bridge'] = gettext("forwarding");
1871
			$ifinfo['bridgeint'] = $bridge;
1872
		}
1873
	}
1874

    
1875
	return $ifinfo;
1876
}
1877

    
1878
//returns cpu speed of processor. Good for determining capabilities of machine
1879
function get_cpu_speed() {
1880
	return get_single_sysctl("hw.clockrate");
1881
}
1882

    
1883
function get_uptime_sec() {
1884
	$boottime = "";
1885
	$matches = "";
1886
	$boottime = get_single_sysctl("kern.boottime");
1887
	preg_match("/sec = (\d+)/", $boottime, $matches);
1888
	$boottime = $matches[1];
1889
	if (intval($boottime) == 0) {
1890
		return 0;
1891
	}
1892

    
1893
	$uptime = time() - $boottime;
1894
	return $uptime;
1895
}
1896

    
1897
function resolve_host_addresses($host, $recordtypes = array(DNS_A, DNS_AAAA, DNS_CNAME), $index = true) {
1898
	$dnsresult = array();
1899
	$resolved = array();
1900
	$errreporting = error_reporting();
1901
	error_reporting($errreporting & ~E_WARNING);// dns_get_record throws a warning if nothing is resolved..
1902
	foreach ($recordtypes as $recordtype) {
1903
		$tmp = dns_get_record($host, $recordtype);
1904
		if (is_array($tmp)) {
1905
			$dnsresult = array_merge($dnsresult, $tmp);
1906
		}
1907
	}
1908
	error_reporting($errreporting);// restore original php warning/error settings.
1909
	foreach ($dnsresult as $item) {
1910
		$newitem = array();
1911
		$newitem['type'] = $item['type'];
1912
		switch ($item['type']) {
1913
			case 'CNAME':
1914
				$newitem['data'] = $item['target'];
1915
				$resolved[] = $newitem;
1916
				break;
1917
			case 'A':
1918
				$newitem['data'] = $item['ip'];
1919
				$resolved[] = $newitem;
1920
				break;
1921
			case 'AAAA':
1922
				$newitem['data'] = $item['ipv6'];
1923
				$resolved[] = $newitem;
1924
				break;
1925
		}
1926
	}
1927
	if ($index == false) {
1928
		foreach ($resolved as $res) {
1929
			$noind[] = $res['data'];
1930
		}
1931
		$resolved = $noind;
1932
	}
1933
	return $resolved;
1934
}
1935

    
1936
function add_hostname_to_watch($hostname) {
1937
	if (!is_dir("/var/db/dnscache")) {
1938
		mkdir("/var/db/dnscache");
1939
	}
1940
	$result = array();
1941
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1942
		$contents = "";
1943
		$domips = resolve_host_addresses($hostname, array(DNS_A), false);
1944
		if (!empty($domips)) {
1945
			foreach ($domips as $ip) {
1946
				$contents .= "$ip\n";
1947
			}
1948
		}
1949
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1950
		/* Remove empty elements */
1951
		$result = array_filter(explode("\n", $contents), 'strlen');
1952
	}
1953
	return $result;
1954
}
1955

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

    
1960
function pfsense_default_state_size() {
1961
	/* get system memory amount */
1962
	$memory = get_memory();
1963
	$physmem = $memory[0];
1964
	/* Be cautious and only allocate 10% of system memory to the state table */
1965
	$max_states = (int) ($physmem/10)*1000;
1966
	return $max_states;
1967
}
1968

    
1969
function pfsense_default_tables_size() {
1970
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1971
	return $current;
1972
}
1973

    
1974
function pfsense_default_table_entries_size() {
1975
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1976
	return (trim($current));
1977
}
1978

    
1979
/* Compare the current hostname DNS to the DNS cache we made
1980
 * if it has changed we return the old records
1981
 * if no change we return false */
1982
function compare_hostname_to_dnscache($hostname) {
1983
	if (!is_dir("/var/db/dnscache")) {
1984
		mkdir("/var/db/dnscache");
1985
	}
1986
	$hostname = trim($hostname);
1987
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1988
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1989
	} else {
1990
		$oldcontents = "";
1991
	}
1992
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1993
		$contents = "";
1994
		$domips = resolve_host_addresses($hostname, array(DNS_A), false);
1995
		if (!empty($domips)) {
1996
			foreach ($domips as $ip) {
1997
				$contents .= "$ip\n";
1998
			}
1999
		}
2000
	}
2001

    
2002
	if (trim($oldcontents) != trim($contents)) {
2003
		if ($g['debug']) {
2004
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
2005
		}
2006
		return ($oldcontents);
2007
	} else {
2008
		return false;
2009
	}
2010
}
2011

    
2012
/*
2013
 * load_crypto() - Load crypto modules if enabled in config.
2014
 */
2015
function load_crypto() {
2016
	global $config, $g;
2017
	$crypto_modules = array('aesni', 'cryptodev');
2018

    
2019
	$enabled_modules = explode('_', $config['system']['crypto_hardware']);
2020

    
2021
	foreach ($enabled_modules as $enmod) {
2022
		if (empty($enmod) || !in_array($enmod, $crypto_modules)) {
2023
			continue;
2024
		}
2025
		if (!is_module_loaded($enmod)) {
2026
			log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $enmod));
2027
			mwexec("/sbin/kldload " . escapeshellarg($enmod));
2028
		}
2029
	}
2030
}
2031

    
2032
/*
2033
 * load_thermal_hardware() - Load temperature monitor kernel module
2034
 */
2035
function load_thermal_hardware() {
2036
	global $config, $g;
2037
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
2038

    
2039
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
2040
		return false;
2041
	}
2042

    
2043
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
2044
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
2045
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
2046
	}
2047
}
2048

    
2049
/****f* pfsense-utils/isvm
2050
 * NAME
2051
 *   isvm
2052
 * INPUTS
2053
 *	none
2054
 * RESULT
2055
 *   returns true if machine is running under a virtual environment
2056
 ******/
2057
function isvm() {
2058
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
2059
	$_gb = exec('/bin/kenv -q smbios.system.product 2>/dev/null', $output, $rc);
2060

    
2061
	if ($rc != 0 || !isset($output[0])) {
2062
		return false;
2063
	}
2064

    
2065
	foreach ($virtualenvs as $virtualenv) {
2066
		if (stripos($output[0], $virtualenv) !== false) {
2067
			return true;
2068
		}
2069
	}
2070

    
2071
	return false;
2072
}
2073

    
2074
function get_freebsd_version() {
2075
	$version = explode(".", php_uname("r"));
2076
	return $version[0];
2077
}
2078

    
2079
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
2080
	global $config, $g;
2081

    
2082
	$fp = fopen($destination, "wb");
2083

    
2084
	if (!$fp) {
2085
		return false;
2086
	}
2087

    
2088
	$ch = curl_init();
2089
	curl_setopt($ch, CURLOPT_URL, $url);
2090
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
2091
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2092
	curl_setopt($ch, CURLOPT_FILE, $fp);
2093
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2094
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2095
	curl_setopt($ch, CURLOPT_HEADER, false);
2096
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2097
	if (!isset($config['system']['do_not_send_uniqueid'])) {
2098
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
2099
	} else {
2100
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2101
	}
2102

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

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

    
2127
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
2128
	global $config, $g;
2129
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
2130
	$file_size = 1;
2131
	$downloaded = 1;
2132
	$first_progress_update = TRUE;
2133
	/* open destination file */
2134
	$fout = fopen($destination, "wb");
2135

    
2136
	if (!$fout) {
2137
		return false;
2138
	}
2139
	/*
2140
	 *      Originally by Author: Keyvan Minoukadeh
2141
	 *      Modified by Scott Ullrich to return Content-Length size
2142
	 */
2143
	$ch = curl_init();
2144
	curl_setopt($ch, CURLOPT_URL, $url);
2145
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
2146
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2147
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
2148
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2149
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
2150
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
2151
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2152
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2153
	if (!isset($config['system']['do_not_send_uniqueid'])) {
2154
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
2155
	} else {
2156
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2157
	}
2158

    
2159
	if (!empty($config['system']['proxyurl'])) {
2160
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2161
		if (!empty($config['system']['proxyport'])) {
2162
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2163
		}
2164
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2165
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2166
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2167
		}
2168
	}
2169

    
2170
	@curl_exec($ch);
2171
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2172
	fclose($fout);
2173
	curl_close($ch);
2174
	if ($http_code == 200) {
2175
		return true;
2176
	} else {
2177
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2178
		unlink_if_exists($destination);
2179
		return false;
2180
	}
2181
}
2182

    
2183
function read_header($ch, $string) {
2184
	global $file_size, $fout;
2185
	$length = strlen($string);
2186
	$regs = "";
2187
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
2188
	if ($regs[2] <> "") {
2189
		$file_size = intval($regs[2]);
2190
	}
2191
	ob_flush();
2192
	return $length;
2193
}
2194

    
2195
function read_body($ch, $string) {
2196
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
2197
	global $pkg_interface;
2198
	$length = strlen($string);
2199
	$downloaded += intval($length);
2200
	if ($file_size > 0) {
2201
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
2202
		$downloadProgress = 100 - $downloadProgress;
2203
	} else {
2204
		$downloadProgress = 0;
2205
	}
2206
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
2207
		if ($sendto == "status") {
2208
			if ($pkg_interface == "console") {
2209
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2210
					$tostatus = $static_status . $downloadProgress . "%";
2211
					if ($downloadProgress == 100) {
2212
						$tostatus = $tostatus . "\r";
2213
					}
2214
					update_status($tostatus);
2215
				}
2216
			} else {
2217
				$tostatus = $static_status . $downloadProgress . "%";
2218
				update_status($tostatus);
2219
			}
2220
		} else {
2221
			if ($pkg_interface == "console") {
2222
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2223
					$tooutput = $static_output . $downloadProgress . "%";
2224
					if ($downloadProgress == 100) {
2225
						$tooutput = $tooutput . "\r";
2226
					}
2227
					update_output_window($tooutput);
2228
				}
2229
			} else {
2230
				$tooutput = $static_output . $downloadProgress . "%";
2231
				update_output_window($tooutput);
2232
			}
2233
		}
2234
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
2235
			update_progress_bar($downloadProgress, $first_progress_update);
2236
			$first_progress_update = FALSE;
2237
		}
2238
		$lastseen = $downloadProgress;
2239
	}
2240
	if ($fout) {
2241
		fwrite($fout, $string);
2242
	}
2243
	ob_flush();
2244
	return $length;
2245
}
2246

    
2247
/*
2248
 *   update_output_window: update bottom textarea dynamically.
2249
 */
2250
function update_output_window($text) {
2251
	global $pkg_interface;
2252
	$log = preg_replace("/\n/", "\\n", $text);
2253
	if ($pkg_interface != "console") {
2254
?>
2255
<script type="text/javascript">
2256
//<![CDATA[
2257
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
2258
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
2259
//]]>
2260
</script>
2261
<?php
2262
	}
2263
	/* ensure that contents are written out */
2264
	ob_flush();
2265
}
2266

    
2267
/*
2268
 *   update_status: update top textarea dynamically.
2269
 */
2270
function update_status($status) {
2271
	global $pkg_interface;
2272

    
2273
	if ($pkg_interface == "console") {
2274
		print ("{$status}");
2275
	}
2276

    
2277
	/* ensure that contents are written out */
2278
	ob_flush();
2279
}
2280

    
2281
/*
2282
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
2283
 */
2284
function update_progress_bar($percent, $first_time) {
2285
	global $pkg_interface;
2286
	if ($percent > 100) {
2287
		$percent = 1;
2288
	}
2289
	if ($pkg_interface <> "console") {
2290
		echo '<script type="text/javascript">';
2291
		echo "\n//<![CDATA[\n";
2292
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
2293
		echo "\n//]]>\n";
2294
		echo '</script>';
2295
	} else {
2296
		if (!($first_time)) {
2297
			echo "\x08\x08\x08\x08\x08";
2298
		}
2299
		echo sprintf("%4d%%", $percent);
2300
	}
2301
}
2302

    
2303
function update_alias_name($new_alias_name, $orig_alias_name) {
2304
	if (!$orig_alias_name) {
2305
		return;
2306
	}
2307

    
2308
	// Firewall rules
2309
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2310
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2311
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2312
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2313
	// NAT Rules
2314
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2315
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2316
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2317
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2318
	update_alias_names_upon_change(array('nat', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2319
	update_alias_names_upon_change(array('nat', 'rule'), array('local-port'), $new_alias_name, $orig_alias_name);
2320
	// NAT 1:1 Rules
2321
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('external'), $new_alias_name, $orig_alias_name);
2322
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2323
	update_alias_names_upon_change(array('nat', 'onetoone'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2324
	// NAT Outbound Rules
2325
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('source', 'network'), $new_alias_name, $orig_alias_name);
2326
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('sourceport'), $new_alias_name, $orig_alias_name);
2327
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2328
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('dstport'), $new_alias_name, $orig_alias_name);
2329
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2330
	// Alias in an alias
2331
	update_alias_names_upon_change(array('aliases', 'alias'), array('address'), $new_alias_name, $orig_alias_name);
2332
}
2333

    
2334
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2335
	global $g, $config, $pconfig, $debug;
2336
	if (!$origname) {
2337
		return;
2338
	}
2339

    
2340
	$sectionref = &$config;
2341
	foreach ($section as $sectionname) {
2342
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2343
			$sectionref = &$sectionref[$sectionname];
2344
		} else {
2345
			return;
2346
		}
2347
	}
2348

    
2349
	if ($debug) {
2350
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2351
		fwrite($fd, print_r($pconfig, true));
2352
	}
2353

    
2354
	if (is_array($sectionref)) {
2355
		foreach ($sectionref as $itemkey => $item) {
2356
			if ($debug) {
2357
				fwrite($fd, "$itemkey\n");
2358
			}
2359

    
2360
			$fieldfound = true;
2361
			$fieldref = &$sectionref[$itemkey];
2362
			foreach ($field as $fieldname) {
2363
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2364
					$fieldref = &$fieldref[$fieldname];
2365
				} else {
2366
					$fieldfound = false;
2367
					break;
2368
				}
2369
			}
2370
			if ($fieldfound && $fieldref == $origname) {
2371
				if ($debug) {
2372
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2373
				}
2374
				$fieldref = $new_alias_name;
2375
			}
2376
		}
2377
	}
2378

    
2379
	if ($debug) {
2380
		fclose($fd);
2381
	}
2382

    
2383
}
2384

    
2385
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2386
	/*
2387
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2388
	 * $type = if set to 'url' then subnets and ips will be returned,
2389
	 *         if set to 'url_ports' port-ranges and ports will be returned
2390
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2391
	 *
2392
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2393
	 */
2394

    
2395
	if (!file_exists($filename)) {
2396
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2397
		return null;
2398
	}
2399

    
2400
	if (filesize($filename) == 0) {
2401
		log_error(sprintf(gettext("Could not process empty file from alias: %s"), $filename));
2402
		return null;
2403
	}
2404
	$fd = @fopen($filename, 'r');
2405
	if (!$fd) {
2406
		log_error(sprintf(gettext("Could not process aliases from alias: %s"), $filename));
2407
		return null;
2408
	}
2409
	$items = array();
2410
	$comments = array();
2411
	/* NOTE: fgetss() is not a typo RTFM before being smart */
2412
	while (($fc = fgetss($fd)) !== FALSE) {
2413
		$tmp = idn_to_ascii(trim($fc, " \t\n\r"));
2414
		if (empty($tmp)) {
2415
			continue;
2416
		}
2417
		if (($kflc) && (strpos($tmp, '#') === 0)) {	// Keep Full Line Comments (lines beginning with #).
2418
			$comments[] = $tmp;
2419
		} else {
2420
			$tmp_str = strstr($tmp, '#', true);
2421
			if (!empty($tmp_str)) {
2422
				$tmp = $tmp_str;
2423
			}
2424
			$tmp_str = strstr($tmp, ' ', true);
2425
			if (!empty($tmp_str)) {
2426
				$tmp = $tmp_str;
2427
			}
2428
			switch ($type) {
2429
				case "url":
2430
				case "urltable":
2431
					if (is_ipaddr($tmp) || is_subnet($tmp)) {
2432
						$items[] = $tmp;
2433
						break;
2434
					}
2435
					if (is_fqdn($tmp)) {
2436
						$results = resolve_host_addresses($tmp, array(DNS_A, DNS_AAAA), false);
2437
						if (!empty($results)) {
2438
							foreach ($results as $ip) {
2439
								if (is_ipaddr($ip)) {
2440
									$items[] = $ip;
2441
								}
2442
							}
2443
						}
2444
					}
2445
					break;
2446
				case "url_ports":
2447
				case "urltable_ports":
2448
					if (is_port_or_range($tmp)) {
2449
						$items[] = $tmp;
2450
					}
2451
					break;
2452
				default:
2453
					/* unknown type */
2454
					break;
2455
				}
2456
			if (count($items) == $max_items) {
2457
				break;
2458
			}
2459
		}
2460
	}
2461
	fclose($fd);
2462
	return array_merge($comments, $items);
2463
}
2464

    
2465
function update_alias_url_data() {
2466
	global $config, $g;
2467

    
2468
	$updated = false;
2469

    
2470
	/* item is a url type */
2471
	$lockkey = lock('aliasurl');
2472
	if (is_array($config['aliases']['alias'])) {
2473
		foreach ($config['aliases']['alias'] as $x => $alias) {
2474
			if (empty($alias['aliasurl'])) {
2475
				continue;
2476
			}
2477

    
2478
			$address = null;
2479
			foreach ($alias['aliasurl'] as $alias_url) {
2480
				/* fetch down and add in */
2481
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2482
				unlink($temp_filename);
2483
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2484
				mkdir($temp_filename);
2485
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2486
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2487
					continue;
2488
				}
2489

    
2490
				/* if the item is tar gzipped then extract */
2491
				if (stripos($alias_url, '.tgz')) {
2492
					if (!process_alias_tgz($temp_filename)) {
2493
						continue;
2494
					}
2495
				}
2496
				if (file_exists("{$temp_filename}/aliases")) {
2497
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2498
					mwexec("/bin/rm -rf {$temp_filename}");
2499
				}
2500
			}
2501
			if ($address != null) {
2502
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2503
				$updated = true;
2504
			}
2505
		}
2506
	}
2507
	unlock($lockkey);
2508

    
2509
	/* Report status to callers as well */
2510
	return $updated;
2511
}
2512

    
2513
function process_alias_tgz($temp_filename) {
2514
	if (!file_exists('/usr/bin/tar')) {
2515
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2516
		return false;
2517
	}
2518
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2519
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2520
	unlink("{$temp_filename}/aliases.tgz");
2521
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2522
	/* foreach through all extracted files and build up aliases file */
2523
	$fd = @fopen("{$temp_filename}/aliases", "w");
2524
	if (!$fd) {
2525
		log_error(sprintf(gettext("Could not open %s/aliases for writing!"), $temp_filename));
2526
		return false;
2527
	}
2528
	foreach ($files_to_process as $f2p) {
2529
		$tmpfd = @fopen($f2p, 'r');
2530
		if (!$tmpfd) {
2531
			log_error(sprintf(gettext('The following file could not be read %1$s from %2$s'), $f2p, $temp_filename));
2532
			continue;
2533
		}
2534
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2535
			fwrite($fd, $tmpbuf);
2536
		}
2537
		fclose($tmpfd);
2538
		unlink($f2p);
2539
	}
2540
	fclose($fd);
2541
	unset($tmpbuf);
2542

    
2543
	return true;
2544
}
2545

    
2546
function version_compare_dates($a, $b) {
2547
	$a_time = strtotime($a);
2548
	$b_time = strtotime($b);
2549

    
2550
	if ((!$a_time) || (!$b_time)) {
2551
		return FALSE;
2552
	} else {
2553
		if ($a_time < $b_time) {
2554
			return -1;
2555
		} elseif ($a_time == $b_time) {
2556
			return 0;
2557
		} else {
2558
			return 1;
2559
		}
2560
	}
2561
}
2562
function version_get_string_value($a) {
2563
	$strs = array(
2564
		0 => "ALPHA-ALPHA",
2565
		2 => "ALPHA",
2566
		3 => "BETA",
2567
		4 => "B",
2568
		5 => "C",
2569
		6 => "D",
2570
		7 => "RC",
2571
		8 => "RELEASE",
2572
		9 => "*"			// Matches all release levels
2573
	);
2574
	$major = 0;
2575
	$minor = 0;
2576
	foreach ($strs as $num => $str) {
2577
		if (substr($a, 0, strlen($str)) == $str) {
2578
			$major = $num;
2579
			$n = substr($a, strlen($str));
2580
			if (is_numeric($n)) {
2581
				$minor = $n;
2582
			}
2583
			break;
2584
		}
2585
	}
2586
	return "{$major}.{$minor}";
2587
}
2588
function version_compare_string($a, $b) {
2589
	// Only compare string parts if both versions give a specific release
2590
	// (If either version lacks a string part, assume intended to match all release levels)
2591
	if (isset($a) && isset($b)) {
2592
		return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
2593
	} else {
2594
		return 0;
2595
	}
2596
}
2597
function version_compare_numeric($a, $b) {
2598
	$a_arr = explode('.', rtrim($a, '.'));
2599
	$b_arr = explode('.', rtrim($b, '.'));
2600

    
2601
	foreach ($a_arr as $n => $val) {
2602
		if (array_key_exists($n, $b_arr)) {
2603
			// So far so good, both have values at this minor version level. Compare.
2604
			if ($val > $b_arr[$n]) {
2605
				return 1;
2606
			} elseif ($val < $b_arr[$n]) {
2607
				return -1;
2608
			}
2609
		} else {
2610
			// a is greater, since b doesn't have any minor version here.
2611
			return 1;
2612
		}
2613
	}
2614
	if (count($b_arr) > count($a_arr)) {
2615
		// b is longer than a, so it must be greater.
2616
		return -1;
2617
	} else {
2618
		// Both a and b are of equal length and value.
2619
		return 0;
2620
	}
2621
}
2622
function pfs_version_compare($cur_time, $cur_text, $remote) {
2623
	// First try date compare
2624
	$v = version_compare_dates($cur_time, $remote);
2625
	if ($v === FALSE) {
2626
		// If that fails, try to compare by string
2627
		// Before anything else, simply test if the strings are equal
2628
		if (($cur_text == $remote) || ($cur_time == $remote)) {
2629
			return 0;
2630
		}
2631
		list($cur_num, $cur_str) = explode('-', $cur_text);
2632
		list($rem_num, $rem_str) = explode('-', $remote);
2633

    
2634
		// First try to compare the numeric parts of the version string.
2635
		$v = version_compare_numeric($cur_num, $rem_num);
2636

    
2637
		// If the numeric parts are the same, compare the string parts.
2638
		if ($v == 0) {
2639
			return version_compare_string($cur_str, $rem_str);
2640
		}
2641
	}
2642
	return $v;
2643
}
2644
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2645
	global $g, $config;
2646

    
2647
	$urltable_prefix = "/var/db/aliastables/";
2648
	$urltable_filename = $urltable_prefix . $name . ".txt";
2649
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2650

    
2651
	// Make the aliases directory if it doesn't exist
2652
	if (!file_exists($urltable_prefix)) {
2653
		mkdir($urltable_prefix);
2654
	} elseif (!is_dir($urltable_prefix)) {
2655
		unlink($urltable_prefix);
2656
		mkdir($urltable_prefix);
2657
	}
2658

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

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

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

    
2673
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2674
			if ($type == "urltable_ports") {
2675
				$parsed_contents = group_ports($parsed_contents, true);
2676
			}
2677
			if (is_array($parsed_contents)) {
2678
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2679
			} else {
2680
				touch($urltable_filename);
2681
			}
2682

    
2683
			/* Remove existing archive and create an up to date archive if RAM disk is enabled. */
2684
			unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz");
2685
			if (isset($config['system']['use_mfs_tmpvar']) && !file_exists("/conf/ram_disks_failed")) {
2686
				mwexec("/usr/bin/tar -czf " . escapeshellarg("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz") . " -C / " . escapeshellarg($urltable_filename));
2687
			}
2688

    
2689
			unlink_if_exists($tmp_urltable_filename);
2690
		} else {
2691
			if (!$validateonly) {
2692
				touch($urltable_filename);
2693
			}
2694
			return false;
2695
		}
2696
		return true;
2697
	} else {
2698
		// File exists, and it doesn't need to be updated.
2699
		return -1;
2700
	}
2701
}
2702

    
2703
function get_include_contents($filename) {
2704
	if (is_file($filename)) {
2705
		ob_start();
2706
		include $filename;
2707
		$contents = ob_get_contents();
2708
		ob_end_clean();
2709
		return $contents;
2710
	}
2711
	return false;
2712
}
2713

    
2714
/* This xml 2 array function is courtesy of the php.net comment section on xml_parse.
2715
 * it is roughly 4 times faster then our existing pfSense parser but due to the large
2716
 * size of the RRD xml dumps this is required.
2717
 * The reason we do not use it for pfSense is that it does not know about array fields
2718
 * which causes it to fail on array fields with single items. Possible Todo?
2719
 */
2720
function xml2array($contents, $get_attributes = 1, $priority = 'tag') {
2721
	if (!function_exists('xml_parser_create')) {
2722
		return array ();
2723
	}
2724
	$parser = xml_parser_create('');
2725
	xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8");
2726
	xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
2727
	xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
2728
	xml_parse_into_struct($parser, trim($contents), $xml_values);
2729
	xml_parser_free($parser);
2730
	if (!$xml_values) {
2731
		return; //Hmm...
2732
	}
2733
	$xml_array = array ();
2734
	$parents = array ();
2735
	$opened_tags = array ();
2736
	$arr = array ();
2737
	$current = & $xml_array;
2738
	$repeated_tag_index = array ();
2739
	foreach ($xml_values as $data) {
2740
		unset ($attributes, $value);
2741
		extract($data);
2742
		$result = array ();
2743
		$attributes_data = array ();
2744
		if (isset ($value)) {
2745
			if ($priority == 'tag') {
2746
				$result = $value;
2747
			} else {
2748
				$result['value'] = $value;
2749
			}
2750
		}
2751
		if (isset ($attributes) and $get_attributes) {
2752
			foreach ($attributes as $attr => $val) {
2753
				if ($priority == 'tag') {
2754
					$attributes_data[$attr] = $val;
2755
				} else {
2756
					$result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
2757
				}
2758
			}
2759
		}
2760
		if ($type == "open") {
2761
			$parent[$level -1] = & $current;
2762
			if (!is_array($current) or (!in_array($tag, array_keys($current)))) {
2763
				$current[$tag] = $result;
2764
				if ($attributes_data) {
2765
					$current[$tag . '_attr'] = $attributes_data;
2766
				}
2767
				$repeated_tag_index[$tag . '_' . $level] = 1;
2768
				$current = &$current[$tag];
2769
			} else {
2770
				if (isset ($current[$tag][0])) {
2771
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2772
					$repeated_tag_index[$tag . '_' . $level]++;
2773
				} else {
2774
					$current[$tag] = array (
2775
						$current[$tag],
2776
						$result
2777
						);
2778
					$repeated_tag_index[$tag . '_' . $level] = 2;
2779
					if (isset ($current[$tag . '_attr'])) {
2780
						$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2781
						unset ($current[$tag . '_attr']);
2782
					}
2783
				}
2784
				$last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
2785
				$current = &$current[$tag][$last_item_index];
2786
			}
2787
		} elseif ($type == "complete") {
2788
			if (!isset ($current[$tag])) {
2789
				$current[$tag] = $result;
2790
				$repeated_tag_index[$tag . '_' . $level] = 1;
2791
				if ($priority == 'tag' and $attributes_data) {
2792
					$current[$tag . '_attr'] = $attributes_data;
2793
				}
2794
			} else {
2795
				if (isset ($current[$tag][0]) and is_array($current[$tag])) {
2796
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2797
					if ($priority == 'tag' and $get_attributes and $attributes_data) {
2798
						$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2799
					}
2800
					$repeated_tag_index[$tag . '_' . $level]++;
2801
				} else {
2802
					$current[$tag] = array (
2803
						$current[$tag],
2804
						$result
2805
						);
2806
					$repeated_tag_index[$tag . '_' . $level] = 1;
2807
					if ($priority == 'tag' and $get_attributes) {
2808
						if (isset ($current[$tag . '_attr'])) {
2809
							$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2810
							unset ($current[$tag . '_attr']);
2811
						}
2812
						if ($attributes_data) {
2813
							$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2814
						}
2815
					}
2816
					$repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
2817
				}
2818
			}
2819
		} elseif ($type == 'close') {
2820
			$current = &$parent[$level -1];
2821
		}
2822
	}
2823
	return ($xml_array);
2824
}
2825

    
2826
function get_country_name($country_code = "ALL") {
2827
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2828
		return "";
2829
	}
2830

    
2831
	$country_names_xml = "/usr/local/share/pfSense/iso_3166-1_list_en.xml";
2832
	$country_names_contents = file_get_contents($country_names_xml);
2833
	$country_names = xml2array($country_names_contents);
2834

    
2835
	if ($country_code == "ALL") {
2836
		$country_list = array();
2837
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2838
			$country_list[] = array(
2839
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2840
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2841
		}
2842
		return $country_list;
2843
	}
2844

    
2845
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2846
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2847
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2848
		}
2849
	}
2850
	return "";
2851
}
2852

    
2853
/* Return the list of country codes to be used on CAs and certs */
2854
function get_cert_country_codes() {
2855
	$countries = get_country_name();
2856

    
2857
	$country_codes = array();
2858
	foreach ($countries as $country) {
2859
		$country_codes[$country['code']] = $country['code'];
2860
	}
2861
	ksort($country_codes);
2862

    
2863
	/* Preserve historical order: None, US, CA, other countries */
2864
	$first_items[''] = gettext("None");
2865
	$first_items['US'] = $country_codes['US'];
2866
	$first_items['CA'] = $country_codes['CA'];
2867
	unset($country_codes['US']);
2868
	unset($country_codes['CA']);
2869

    
2870
	return array_merge($first_items, $country_codes);
2871
}
2872

    
2873
/* sort by interface only, retain the original order of rules that apply to
2874
   the same interface */
2875
function filter_rules_sort() {
2876
	global $config;
2877

    
2878
	init_config_arr(array('filter', 'rule'));
2879
	/* mark each rule with the sequence number (to retain the order while sorting) */
2880
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2881
		if (!is_array($config['filter']['rule'][$i])) {
2882
			$config['filter']['rule'][$i] = array();
2883
		}
2884
		$config['filter']['rule'][$i]['seq'] = $i;
2885
	}
2886

    
2887
	usort($config['filter']['rule'], "filter_rules_compare");
2888

    
2889
	/* strip the sequence numbers again */
2890
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2891
		unset($config['filter']['rule'][$i]['seq']);
2892
	}
2893
}
2894
function filter_rules_compare($a, $b) {
2895
	if (isset($a['floating']) && isset($b['floating'])) {
2896
		return $a['seq'] - $b['seq'];
2897
	} else if (isset($a['floating'])) {
2898
		return -1;
2899
	} else if (isset($b['floating'])) {
2900
		return 1;
2901
	} else if ($a['interface'] == $b['interface']) {
2902
		return $a['seq'] - $b['seq'];
2903
	} else {
2904
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2905
	}
2906
}
2907

    
2908
function generate_ipv6_from_mac($mac) {
2909
	$elements = explode(":", $mac);
2910
	if (count($elements) <> 6) {
2911
		return false;
2912
	}
2913

    
2914
	$i = 0;
2915
	$ipv6 = "fe80::";
2916
	foreach ($elements as $byte) {
2917
		if ($i == 0) {
2918
			$hexadecimal = substr($byte, 1, 2);
2919
			$bitmap = base_convert($hexadecimal, 16, 2);
2920
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2921
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2922
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2923
		}
2924
		$ipv6 .= $byte;
2925
		if ($i == 1) {
2926
			$ipv6 .= ":";
2927
		}
2928
		if ($i == 3) {
2929
			$ipv6 .= ":";
2930
		}
2931
		if ($i == 2) {
2932
			$ipv6 .= "ff:fe";
2933
		}
2934

    
2935
		$i++;
2936
	}
2937
	return $ipv6;
2938
}
2939

    
2940
/****f* pfsense-utils/load_mac_manufacturer_table
2941
 * NAME
2942
 *   load_mac_manufacturer_table
2943
 * INPUTS
2944
 *   none
2945
 * RESULT
2946
 *   returns associative array with MAC-Manufacturer pairs
2947
 ******/
2948
function load_mac_manufacturer_table() {
2949
	/* load MAC-Manufacture data from the file */
2950
	$macs = false;
2951
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2952
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2953
	}
2954
	if ($macs) {
2955
		foreach ($macs as $line) {
2956
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2957
				/* store values like this $mac_man['000C29']='VMware' */
2958
				$mac_man["$matches[1]"] = $matches[2];
2959
			}
2960
		}
2961
		return $mac_man;
2962
	} else {
2963
		return -1;
2964
	}
2965

    
2966
}
2967

    
2968
/****f* pfsense-utils/is_ipaddr_configured
2969
 * NAME
2970
 *   is_ipaddr_configured
2971
 * INPUTS
2972
 *   IP Address to check.
2973
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2974
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2975
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2976
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2977
 *     If check_subnets is true and cidrprefix is specified,
2978
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2979
 * RESULT
2980
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2981
*/
2982
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2983
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2984
		return true;
2985
	}
2986
	return false;
2987
}
2988

    
2989
/****f* pfsense-utils/where_is_ipaddr_configured
2990
 * NAME
2991
 *   where_is_ipaddr_configured
2992
 * INPUTS
2993
 *   IP Address to check.
2994
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2995
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2996
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2997
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2998
 *     If check_subnets is true and cidrprefix is specified,
2999
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
3000
 * RESULT
3001
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
3002
 *   If there are no matches then an empty array is returned.
3003
*/
3004
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
3005
	global $config;
3006

    
3007
	$where_configured = array();
3008

    
3009
	$pos = strpos($ignore_if, '_virtualip');
3010
	if ($pos !== false) {
3011
		$ignore_vip_id = substr($ignore_if, $pos+10);
3012
		$ignore_vip_if = substr($ignore_if, 0, $pos);
3013
	} else {
3014
		$ignore_vip_id = -1;
3015
		$ignore_vip_if = $ignore_if;
3016
	}
3017

    
3018
	$isipv6 = is_ipaddrv6($ipaddr);
3019

    
3020
	if ($isipv6) {
3021
		$ipaddr = text_to_compressed_ip6($ipaddr);
3022
	}
3023

    
3024
	if ($check_subnets) {
3025
		$cidrprefix = intval($cidrprefix);
3026
		if ($isipv6) {
3027
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
3028
				$cidrprefix = 128;
3029
			}
3030
		} else {
3031
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
3032
				$cidrprefix = 32;
3033
			}
3034
		}
3035
		$iflist = get_configured_interface_list();
3036
		foreach ($iflist as $if => $ifname) {
3037
			if ($ignore_if == $if) {
3038
				continue;
3039
			}
3040

    
3041
			if ($isipv6) {
3042
				$if_ipv6 = get_interface_ipv6($if);
3043
				$if_snbitsv6 = get_interface_subnetv6($if);
3044
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
3045
					$where_entry = array();
3046
					$where_entry['if'] = $if;
3047
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
3048
					$where_configured[] = $where_entry;
3049
				}
3050
			} else {
3051
				$if_ipv4 = get_interface_ip($if);
3052
				$if_snbitsv4 = get_interface_subnet($if);
3053
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
3054
					$where_entry = array();
3055
					$where_entry['if'] = $if;
3056
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
3057
					$where_configured[] = $where_entry;
3058
				}
3059
			}
3060
		}
3061
	} else {
3062
		if ($isipv6) {
3063
			$interface_list_ips = get_configured_ipv6_addresses();
3064
		} else {
3065
			$interface_list_ips = get_configured_ip_addresses();
3066
		}
3067

    
3068
		foreach ($interface_list_ips as $if => $ilips) {
3069
			if ($ignore_if == $if) {
3070
				continue;
3071
			}
3072
			if (strcasecmp($ipaddr, $ilips) == 0) {
3073
				$where_entry = array();
3074
				$where_entry['if'] = $if;
3075
				$where_entry['ip_or_subnet'] = $ilips;
3076
				$where_configured[] = $where_entry;
3077
			}
3078
		}
3079
	}
3080

    
3081
	if ($check_localip) {
3082
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, text_to_compressed_ip6($config['l2tp']['localip'])) == 0)) {
3083
			$where_entry = array();
3084
			$where_entry['if'] = 'l2tp';
3085
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
3086
			$where_configured[] = $where_entry;
3087
		}
3088
	}
3089

    
3090
	return $where_configured;
3091
}
3092

    
3093
/****f* pfsense-utils/pfSense_handle_custom_code
3094
 * NAME
3095
 *   pfSense_handle_custom_code
3096
 * INPUTS
3097
 *   directory name to process
3098
 * RESULT
3099
 *   globs the directory and includes the files
3100
 */
3101
function pfSense_handle_custom_code($src_dir) {
3102
	// Allow extending of the nat edit page and include custom input validation
3103
	if (is_dir("$src_dir")) {
3104
		$cf = glob($src_dir . "/*.inc");
3105
		foreach ($cf as $nf) {
3106
			if ($nf == "." || $nf == "..") {
3107
				continue;
3108
			}
3109
			// Include the extra handler
3110
			include_once("$nf");
3111
		}
3112
	}
3113
}
3114

    
3115
function set_language() {
3116
	global $config, $g;
3117

    
3118
	if (!empty($config['system']['language'])) {
3119
		$lang = $config['system']['language'];
3120
	} elseif (!empty($g['language'])) {
3121
		$lang = $g['language'];
3122
	}
3123
	$lang .= ".UTF-8";
3124

    
3125
	putenv("LANG={$lang}");
3126
	setlocale(LC_ALL, $lang);
3127
	textdomain("pfSense");
3128
	bindtextdomain("pfSense", "/usr/local/share/locale");
3129
	bind_textdomain_codeset("pfSense", $lang);
3130
}
3131

    
3132
function get_locale_list() {
3133
	$locales = array(
3134
		"bs" => gettext("Bosnian"),
3135
		"zh_CN" => gettext("Chinese"),
3136
		"zh_Hans_CN" => gettext("Chinese (Simplified, China)"),
3137
		"zh_Hans_HK" => gettext("Chinese (Simplified, Hong Kong SAR China)"),
3138
		"zh_Hant_TW" => gettext("Chinese (Traditional, Taiwan)"),
3139
		"nl" => gettext("Dutch"),
3140
		"en_US" => gettext("English"),
3141
		"fr" => gettext("French"),
3142
		"de_DE" => gettext("German (Germany)"),
3143
		"it" => gettext("Italian"),
3144
		"ko" => gettext("Korean"),
3145
		"nb" => gettext("Norwegian Bokmål"),
3146
		"pl" => gettext("Polish"),
3147
		"pt_PT" => gettext("Portuguese"),
3148
		"pt_BR" => gettext("Portuguese (Brazil)"),
3149
		"ru" => gettext("Russian"),
3150
		"es" => gettext("Spanish"),
3151
		"es_AR" => gettext("Spanish (Argentina)"),
3152
	);
3153

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

    
3158
	//asort($locales);
3159

    
3160
	return $locales;
3161
}
3162

    
3163
function return_hex_ipv4($ipv4) {
3164
	if (!is_ipaddrv4($ipv4)) {
3165
		return(false);
3166
	}
3167

    
3168
	/* we need the hex form of the interface IPv4 address */
3169
	$ip4arr = explode(".", $ipv4);
3170
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
3171
}
3172

    
3173
function convert_ipv6_to_128bit($ipv6) {
3174
	if (!is_ipaddrv6($ipv6)) {
3175
		return(false);
3176
	}
3177

    
3178
	$ip6arr = array();
3179
	$ip6prefix = Net_IPv6::uncompress($ipv6);
3180
	$ip6arr = explode(":", $ip6prefix);
3181
	/* binary presentation of the prefix for all 128 bits. */
3182
	$ip6prefixbin = "";
3183
	foreach ($ip6arr as $element) {
3184
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3185
	}
3186
	return($ip6prefixbin);
3187
}
3188

    
3189
function convert_128bit_to_ipv6($ip6bin) {
3190
	if (strlen($ip6bin) <> 128) {
3191
		return(false);
3192
	}
3193

    
3194
	$ip6arr = array();
3195
	$ip6binarr = array();
3196
	$ip6binarr = str_split($ip6bin, 16);
3197
	foreach ($ip6binarr as $binpart) {
3198
		$ip6arr[] = dechex(bindec($binpart));
3199
	}
3200
	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
3201

    
3202
	return($ip6addr);
3203
}
3204

    
3205

    
3206
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3207
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3208
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3209
/* 6to4 is 16 bits, e.g. 65535 */
3210
function calculate_ipv6_delegation_length($if) {
3211
	global $config;
3212

    
3213
	if (!is_array($config['interfaces'][$if])) {
3214
		return false;
3215
	}
3216

    
3217
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3218
		case "6to4":
3219
			$pdlen = 16;
3220
			break;
3221
		case "6rd":
3222
			$rd6cfg = $config['interfaces'][$if];
3223
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3224
			$pdlen = (64 - ((int) $rd6plen[1] + (32 - (int) $rd6cfg['prefix-6rd-v4plen'])));
3225
			break;
3226
		case "dhcp6":
3227
			$dhcp6cfg = $config['interfaces'][$if];
3228
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3229
			break;
3230
		default:
3231
			$pdlen = 0;
3232
			break;
3233
	}
3234
	return($pdlen);
3235
}
3236

    
3237
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3238
	$prefix = Net_IPv6::uncompress($prefix, true);
3239
	$suffix = Net_IPv6::uncompress($suffix, true);
3240

    
3241
	/*
3242
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3243
	 *                ^^^^ ^
3244
	 *                |||| \-> 64
3245
	 *                |||\---> 63, 62, 61, 60
3246
	 *                ||\----> 56
3247
	 *                |\-----> 52
3248
	 *                \------> 48
3249
	 */
3250

    
3251
	switch ($len) {
3252
	case 48:
3253
		$prefix_len = 15;
3254
		break;
3255
	case 52:
3256
		$prefix_len = 16;
3257
		break;
3258
	case 56:
3259
		$prefix_len = 17;
3260
		break;
3261
	case 59:
3262
	case 60:
3263
		$prefix_len = 18;
3264
		break;
3265
	/*
3266
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
3267
	 * we let user chose this bit it can end up out of PD network
3268
	 *
3269
	 * Leave this with 20 for now until we find a way to let user
3270
	 * chose it. The side-effect is users with PD with one of these
3271
	 * lengths will not be able to setup DHCP server range for full
3272
	 * PD size, only for last /64 network
3273
	 */
3274
	case 63:
3275
	case 62:
3276
	case 61:
3277
	default:
3278
		$prefix_len = 20;
3279
		break;
3280
	}
3281

    
3282
	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
3283
	    substr($suffix, $prefix_len));
3284
}
3285

    
3286
function dhcpv6_pd_str_help($pdlen) {
3287
	$result = '';
3288

    
3289
	switch ($pdlen) {
3290
	case 48:
3291
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
3292
		break;
3293
	case 52:
3294
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
3295
		break;
3296
	case 56:
3297
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
3298
		break;
3299
	case 59:
3300
	case 60:
3301
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
3302
		break;
3303
	/*
3304
	 * XXX 63, 62 and 61 should use same mask as 60 but if
3305
	 * we let the user choose this bit it can end up out of PD network
3306
	 *
3307
	 * Leave this with the same as 64 for now until we find a way to
3308
	 * let the user choose it. The side-effect is users with PD with one
3309
	 * of these lengths will not be able to setup DHCP server ranges
3310
	 * for full PD size, only for last /64 network
3311
	 */
3312
	case 61:
3313
	case 62:
3314
	case 63:
3315
	case 64:
3316
	default:
3317
		$result = '::xxxx:xxxx:xxxx:xxxx';
3318
		break;
3319
	}
3320

    
3321
	return $result;
3322
}
3323

    
3324
function huawei_rssi_to_string($rssi) {
3325
	$dbm = array();
3326
	$i = 0;
3327
	$dbstart = -113;
3328
	while ($i < 32) {
3329
		$dbm[$i] = $dbstart + ($i * 2);
3330
		$i++;
3331
	}
3332
	$percent = round(($rssi / 31) * 100);
3333
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3334
	return $string;
3335
}
3336

    
3337
function huawei_mode_to_string($mode, $submode) {
3338
	$modes[0] = gettext("None");
3339
	$modes[1] = "AMPS";
3340
	$modes[2] = "CDMA";
3341
	$modes[3] = "GSM/GPRS";
3342
	$modes[4] = "HDR";
3343
	$modes[5] = "WCDMA";
3344
	$modes[6] = "GPS";
3345

    
3346
	$submodes[0] = gettext("No Service");
3347
	$submodes[1] = "GSM";
3348
	$submodes[2] = "GPRS";
3349
	$submodes[3] = "EDGE";
3350
	$submodes[4] = "WCDMA";
3351
	$submodes[5] = "HSDPA";
3352
	$submodes[6] = "HSUPA";
3353
	$submodes[7] = "HSDPA+HSUPA";
3354
	$submodes[8] = "TD-SCDMA";
3355
	$submodes[9] = "HSPA+";
3356
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3357
	return $string;
3358
}
3359

    
3360
function huawei_service_to_string($state) {
3361
	$modes[0] = gettext("No Service");
3362
	$modes[1] = gettext("Restricted Service");
3363
	$modes[2] = gettext("Valid Service");
3364
	$modes[3] = gettext("Restricted Regional Service");
3365
	$modes[4] = gettext("Powersaving Service");
3366
	$modes[255] = gettext("Unknown Service");
3367
	$string = $modes[$state];
3368
	return $string;
3369
}
3370

    
3371
function huawei_simstate_to_string($state) {
3372
	$modes[0] = gettext("Invalid SIM/locked State");
3373
	$modes[1] = gettext("Valid SIM State");
3374
	$modes[2] = gettext("Invalid SIM CS State");
3375
	$modes[3] = gettext("Invalid SIM PS State");
3376
	$modes[4] = gettext("Invalid SIM CS/PS State");
3377
	$modes[255] = gettext("Missing SIM State");
3378
	$string = $modes[$state];
3379
	return $string;
3380
}
3381

    
3382
function zte_rssi_to_string($rssi) {
3383
	return huawei_rssi_to_string($rssi);
3384
}
3385

    
3386
function zte_mode_to_string($mode, $submode) {
3387
	$modes[0] = gettext("No Service");
3388
	$modes[1] = gettext("Limited Service");
3389
	$modes[2] = "GPRS";
3390
	$modes[3] = "GSM";
3391
	$modes[4] = "UMTS";
3392
	$modes[5] = "EDGE";
3393
	$modes[6] = "HSDPA";
3394

    
3395
	$submodes[0] = "CS_ONLY";
3396
	$submodes[1] = "PS_ONLY";
3397
	$submodes[2] = "CS_PS";
3398
	$submodes[3] = "CAMPED";
3399
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3400
	return $string;
3401
}
3402

    
3403
function zte_service_to_string($service) {
3404
	$modes[0] = gettext("Initializing Service");
3405
	$modes[1] = gettext("Network Lock error Service");
3406
	$modes[2] = gettext("Network Locked Service");
3407
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3408
	$string = $modes[$service];
3409
	return $string;
3410
}
3411

    
3412
function zte_simstate_to_string($state) {
3413
	$modes[0] = gettext("No action State");
3414
	$modes[1] = gettext("Network lock State");
3415
	$modes[2] = gettext("(U)SIM card lock State");
3416
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3417
	$string = $modes[$state];
3418
	return $string;
3419
}
3420

    
3421
function get_configured_pppoe_server_interfaces() {
3422
	global $config;
3423
	$iflist = array();
3424
	if (is_array($config['pppoes']['pppoe'])) {
3425
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3426
			if ($pppoe['mode'] == "server") {
3427
				$int = "poes". $pppoe['pppoeid'];
3428
				$iflist[$int] = strtoupper($int);
3429
			}
3430
		}
3431
	}
3432
	return $iflist;
3433
}
3434

    
3435
function get_pppoes_child_interfaces($ifpattern) {
3436
	$if_arr = array();
3437
	if ($ifpattern == "") {
3438
		return;
3439
	}
3440

    
3441
	exec("/sbin/ifconfig", $out, $ret);
3442
	foreach ($out as $line) {
3443
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3444
			$if_arr[] = $match[1];
3445
		}
3446
	}
3447
	return $if_arr;
3448

    
3449
}
3450

    
3451
/****f* pfsense-utils/pkg_call_plugins
3452
 * NAME
3453
 *   pkg_call_plugins
3454
 * INPUTS
3455
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3456
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3457
 * RESULT
3458
 *   returns associative array results from the plugin calls for each package
3459
 * NOTES
3460
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3461
 ******/
3462
function pkg_call_plugins($plugin_type, $plugin_params) {
3463
	global $g, $config;
3464
	$results = array();
3465
	if (!is_array($config['installedpackages']['package'])) {
3466
		return $results;
3467
	}
3468
	foreach ($config['installedpackages']['package'] as $package) {
3469
		if (is_array($package['plugins']['item'])) {
3470
			foreach ($package['plugins']['item'] as $plugin) {
3471
				if ($plugin['type'] == $plugin_type) {
3472
					if (file_exists($package['include_file'])) {
3473
						require_once($package['include_file']);
3474
					} else {
3475
						continue;
3476
					}
3477
					$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3478
					$plugin_function = $pkgname . '_'. $plugin_type;
3479
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3480
				}
3481
			}
3482
		}
3483
	}
3484
	return $results;
3485
}
3486

    
3487
// Convert IPv6 addresses to lower case
3488
function addrtolower($ip) {
3489
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3490
		return(strtolower($ip));
3491
	} else {
3492
		return($ip);
3493
	}
3494
}
3495

    
3496
function compare_by_name($a, $b) {
3497
	return strcasecmp($a['name'], $b['name']);
3498
}
3499

    
3500
/****f* pfsense-utils/getarraybyref
3501
 * NAME
3502
 *   getarraybyref
3503
 * INPUTS
3504
 *   $array the array of which a items array needs to be found.
3505
 *   $args.. the sub-items to be retrieved/created
3506
 * RESULT
3507
 *   returns the array that was retrieved from configuration, its created if it does not exist
3508
 * NOTES
3509
 *   Used by haproxy / acme / others.?. .
3510
 *   can be used like this:  $a_certificates = getarraybyref($config, 'installedpackages', 'acme', 'certificates', 'item');
3511
 ******/
3512
function &getarraybyref(&$array) {
3513
	if (!isset($array)) {
3514
		return false;
3515
	}
3516
	if (!is_array($array)) {
3517
		$array = array();
3518
	}
3519
	$item = &$array;
3520
	$arg = func_get_args();
3521
	for($i = 1; $i < count($arg); $i++) {
3522
		$itemindex = $arg[$i];
3523
		if (!is_array($item[$itemindex])) {
3524
			$item[$itemindex] = array();
3525
		}
3526
		$item = &$item[$itemindex];
3527
	}
3528
	return $item;
3529
}
3530

    
3531
/****f* pfsense-utils/send_download_data
3532
 * NAME
3533
 *   send_download_data - Send content to a user's browser as a file to download
3534
 * INPUTS
3535
 *   $type        : The type of download, either 'data' to send the contents of
3536
 *                    a variable or 'file' to send the contents of a file on the
3537
 *                    filesystem.
3538
 *   $content     : For 'data' type, the content to send the user. For 'file'
3539
 *                    type, the full path to the file to send.
3540
 *   $userfilename: The filename presented to the user when downloading. For
3541
 *                    'file' type, this may be omitted and the basename of
3542
 *                    $content will be used instead.
3543
 *   $contenttype : MIME content type of the data. Default "application/octet-stream"
3544
 * RESULT
3545
 *   Sends the data to the browser as a file to download.
3546
 ******/
3547

    
3548
function send_user_download($type = 'data', $content, $userfilename = "", $contenttype = "application/octet-stream") {
3549
	/* If the type is 'file', then use the file size, otherwise use the size of the data to send */
3550
	$size = ($type == 'file') ? filesize($content) : strlen($content);
3551

    
3552
	/* If the filename to pass to the user is empty, assume it to be the filename being read. */
3553
	$name = basename((($type == 'file') && empty($userfilename)) ? $content : $userfilename);
3554

    
3555
	/* Cannot determine the filename, so bail. */
3556
	if (empty($name)) {
3557
		exit;
3558
	}
3559

    
3560
	/* Send basic download headers */
3561
	header("Content-Type: {$contenttype}");
3562
	header("Content-Length: {$size}");
3563
	header("Content-Disposition: attachment; filename=" . urlencode($name));
3564

    
3565
	/* Send cache headers */
3566
	if (isset($_SERVER['HTTPS'])) {
3567
		header('Pragma: ');
3568
		header('Cache-Control: ');
3569
	} else {
3570
		header("Pragma: private");
3571
		header("Cache-Control: private, must-revalidate");
3572
	}
3573

    
3574
	/* Ensure output buffering is off so PHP does not consume
3575
	 * memory in readfile(). https://redmine.pfsense.org/issues/9239 */
3576
	while (ob_get_level()) {
3577
		@ob_end_clean();
3578
	}
3579

    
3580
	/* Send the data to the user */
3581
	if ($type == 'file') {
3582
		readfile($content);
3583
	} else {
3584
		echo $content;
3585
	}
3586

    
3587
	/* Flush any remaining output buffer */
3588
	@ob_end_flush();
3589
	exit;
3590
}
3591

    
3592
// Test whether the hostname in a URL can be resolved with a very short timeout
3593
function is_url_hostname_resolvable($url) {
3594
	$urlhostname = parse_url($url, PHP_URL_HOST);
3595
	if (empty($urlhostname)) {
3596
		return false;
3597
	}
3598
	putenv("RES_OPTIONS=timeout:3 attempts:1");
3599
	$resolvable = ($urlhostname !== gethostbyname($urlhostname));
3600
	putenv("RES_OPTIONS");
3601
	return $resolvable;
3602
}
3603

    
3604
function get_pf_timeouts () {
3605
	$pftimeout = array();
3606
	exec("/sbin/pfctl -st", $pfctlst, $retval);
3607
	if ($retval == 0) {
3608
		foreach ($pfctlst as $pfst) {
3609
			preg_match('/([a-z]+)\.([a-z]+)\s+([0-9]+)/', $pfst, $timeout);
3610
			if ($timeout[1] == "other") {
3611
				$proto = "Other";
3612
			} else {
3613
				$proto = strtoupper($timeout[1]);
3614
			}
3615
			if ($timeout[2] == "finwait") {
3616
				$type = "FIN Wait";
3617
			} else {
3618
				$type = ucfirst($timeout[2]);
3619
			}
3620
			$pftimeout[$proto][$type]['name'] = $proto . " " . $type;
3621
			$pftimeout[$proto][$type]['keyname'] = $timeout[1] . $timeout[2] . "timeout";
3622
			$pftimeout[$proto][$type]['value'] = $timeout[3];
3623
		}
3624
	}
3625
	return $pftimeout;
3626
}
3627

    
3628
?>
(38-38/60)