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", "hw.hn.vf_transparent",
1212
	    "hw.hn.use_if_start");
1213
	if (!$local) {
1214
		/* These values should only be filtered in loader.conf, not .local */
1215
		$remove = array_merge($remove,
1216
		    array("autoboot_delay", "console", "comconsole_speed",
1217
		    "boot_multicons", "boot_serial", "hint.uart.0.flags",
1218
		    "hint.uart.1.flags"));
1219
	}
1220
	foreach ($input_split as $line) {
1221
		if (empty($line)) {
1222
			continue;
1223
		}
1224
		$skip = false;
1225
		list($name, $value) = explode('=', $line, 2);
1226
		foreach($remove as $rid => $rkey) {
1227
			if (strncasecmp(trim($name), $rkey, strlen($rkey)) == 0) {
1228
				$skip = true;
1229
				break;
1230
			}
1231
		}
1232
		if (!$skip) {
1233
			$data[] = $line;
1234
		}
1235
	}
1236

    
1237
	return ($data);
1238
}
1239

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

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

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

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

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

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

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

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

    
1320
	if ($specific_platform['name'] == 'RCC-VE' ||
1321
	    $specific_platform['name'] == 'RCC' ||
1322
	    $specific_platform['name'] == 'SG-2220') {
1323
		$data[] = 'comconsole_port="0x2F8"';
1324
		$data[] = 'hint.uart.0.flags="0x00"';
1325
		$data[] = 'hint.uart.1.flags="0x10"';
1326
	}
1327
	$data[] = 'autoboot_delay="3"';
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
	if (isset($config['system']['hn_altq_enable'])) {
1341
		$data[] = 'hw.hn.vf_transparent="0"';
1342
		$data[] = 'hw.hn.use_if_start="1"';
1343
	}
1344

    
1345
	safe_write_file($loader_conf_file, $data);
1346

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

    
1356
}
1357

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

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

    
1365
	$ttys = file_get_contents($ttys_file);
1366
	$ttys_split = explode("\n", $ttys);
1367

    
1368
	$data = array();
1369

    
1370
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1371

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

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

    
1386
	$found = array();
1387

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

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

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

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

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

    
1434
	safe_write_file($ttys_file, $data);
1435

    
1436
	unset($ttys, $ttys_file, $ttys_split, $data);
1437

    
1438
	if ($when != "upgrade") {
1439
		reload_ttys();
1440
	}
1441

    
1442
	return;
1443
}
1444

    
1445
function is_serial_enabled() {
1446
	global $g, $config;
1447

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

    
1453
	return true;
1454
}
1455

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

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

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

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

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

    
1485
	return false;
1486
}
1487

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

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

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

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

    
1510
	return false;
1511
}
1512

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

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

    
1521
	$dhcpdv6cfg = $config['dhcpdv6'];
1522
	$Iflist = get_configured_interface_list();
1523

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

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

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

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

    
1543
		return true;
1544
	}
1545

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

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

    
1560
		$ifcfgsnv6 = get_interface_subnetv6($if);
1561
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1562

    
1563
		if (!is_ipaddrv6($subnetv6)) {
1564
			continue;
1565
		}
1566

    
1567
		return true;
1568
	}
1569

    
1570
	return false;
1571
}
1572

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

    
1577
	$pppoeenable = false;
1578

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

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

    
1589
	return $pppoeenable;
1590
}
1591

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

    
1606
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1607

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1877
	return $ifinfo;
1878
}
1879

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

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

    
1895
	$uptime = time() - $boottime;
1896
	return $uptime;
1897
}
1898

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

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

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

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

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

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

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

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

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

    
2021
	$enabled_modules = explode('_', $config['system']['crypto_hardware']);
2022

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

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

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

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

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

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

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

    
2073
	return false;
2074
}
2075

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

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

    
2084
	$fp = fopen($destination, "wb");
2085

    
2086
	if (!$fp) {
2087
		return false;
2088
	}
2089

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

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

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

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

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

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

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

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

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

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

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

    
2275
	if ($pkg_interface == "console") {
2276
		print ("{$status}");
2277
	}
2278

    
2279
	/* ensure that contents are written out */
2280
	ob_flush();
2281
}
2282

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

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

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

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

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

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

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

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

    
2381
	if ($debug) {
2382
		fclose($fd);
2383
	}
2384

    
2385
}
2386

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

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

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

    
2467
function update_alias_url_data() {
2468
	global $config, $g;
2469

    
2470
	$updated = false;
2471

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

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

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

    
2511
	/* Report status to callers as well */
2512
	return $updated;
2513
}
2514

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

    
2545
	return true;
2546
}
2547

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2872
	return array_merge($first_items, $country_codes);
2873
}
2874

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

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

    
2889
	usort($config['filter']['rule'], "filter_rules_compare");
2890

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

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

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

    
2937
		$i++;
2938
	}
2939
	return $ipv6;
2940
}
2941

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

    
2968
}
2969

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

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

    
3009
	$where_configured = array();
3010

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

    
3020
	$isipv6 = is_ipaddrv6($ipaddr);
3021

    
3022
	if ($isipv6) {
3023
		$ipaddr = text_to_compressed_ip6($ipaddr);
3024
	}
3025

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

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

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

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

    
3092
	return $where_configured;
3093
}
3094

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

    
3117
function set_language() {
3118
	global $config, $g;
3119

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

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

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

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

    
3160
	//asort($locales);
3161

    
3162
	return $locales;
3163
}
3164

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

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

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

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

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

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

    
3204
	return($ip6addr);
3205
}
3206

    
3207

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

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

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

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

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

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

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

    
3288
function dhcpv6_pd_str_help($pdlen) {
3289
	$result = '';
3290

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

    
3323
	return $result;
3324
}
3325

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

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

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

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

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

    
3384
function zte_rssi_to_string($rssi) {
3385
	return huawei_rssi_to_string($rssi);
3386
}
3387

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

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

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

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

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

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

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

    
3451
}
3452

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3630
?>
(38-38/60)