Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

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

    
196
		$css = array_merge($pfscss, $betacss, $usrcss);
197

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

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

    
217
	$csslist = get_css_files();
218

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

    
223
	$section->addInput(new Form_Select(
224
		'webguicss',
225
		'Theme',
226
		$value,
227
		$csslist
228
	))->setHelp('Choose an alternative css file (if installed) to change the appearance of the webConfigurator. css files are located in /usr/local/www/css/%s', '<span id="csstxt"></span>');
229
}
230

    
231
/****f* pfsense-utils/gen_webguifixedmenu_field
232
 * NAME
233
 *   gen_webguifixedmenu_field
234
 * INPUTS
235
 *   Pointer to section object
236
 *   Initial value for the field
237
 * RESULT
238
 *   no return value, section object is updated
239
 ******/
240
function gen_webguifixedmenu_field(&$section, $value) {
241

    
242
	$section->addInput(new Form_Select(
243
		'webguifixedmenu',
244
		'Top Navigation',
245
		$value,
246
		["" => gettext("Scrolls with page"), "fixed" => gettext("Fixed (Remains visible at top of page)")]
247
	))->setHelp("The fixed option is intended for large screens only.");
248
}
249

    
250
/****f* pfsense-utils/gen_webguihostnamemenu_field
251
 * NAME
252
 *   gen_webguihostnamemenu_field
253
 * INPUTS
254
 *   Pointer to section object
255
 *   Initial value for the field
256
 * RESULT
257
 *   no return value, section object is updated
258
 ******/
259
function gen_webguihostnamemenu_field(&$section, $value) {
260

    
261
	$section->addInput(new Form_Select(
262
		'webguihostnamemenu',
263
		'Hostname in Menu',
264
		$value,
265
		["" => gettext("Default (No hostname)"), "hostonly" => gettext("Hostname only"), "fqdn" => gettext("Fully Qualified Domain Name")]
266
	))->setHelp("Replaces the Help menu title in the Navbar with the system hostname or FQDN.");
267
}
268

    
269
/****f* pfsense-utils/gen_dashboardcolumns_field
270
 * NAME
271
 *   gen_dashboardcolumns_field
272
 * INPUTS
273
 *   Pointer to section object
274
 *   Initial value for the field
275
 * RESULT
276
 *   no return value, section object is updated
277
 ******/
278
function gen_dashboardcolumns_field(&$section, $value) {
279

    
280
	if (($value < 1) || ($value > 6)) {
281
		$value = 2;
282
	}
283

    
284
	$section->addInput(new Form_Input(
285
		'dashboardcolumns',
286
		'Dashboard Columns',
287
		'number',
288
		$value,
289
		['min' => 1, 'max' => 6]
290
	));
291
}
292

    
293
/****f* pfsense-utils/gen_interfacessort_field
294
 * NAME
295
 *   gen_interfacessort_field
296
 * INPUTS
297
 *   Pointer to section object
298
 *   Initial value for the field
299
 * RESULT
300
 *   no return value, section object is updated
301
 ******/
302
function gen_interfacessort_field(&$section, $value) {
303

    
304
	$section->addInput(new Form_Checkbox(
305
		'interfacessort',
306
		'Interfaces Sort',
307
		'Sort Alphabetically',
308
		$value
309
	))->setHelp('If selected, lists of interfaces will be sorted by description, otherwise they are listed wan,lan,optn...');
310
}
311

    
312
/****f* pfsense-utils/gen_associatedpanels_fields
313
 * NAME
314
 *   gen_associatedpanels_fields
315
 * INPUTS
316
 *   Pointer to section object
317
 *   Initial value for each of the fields
318
 * RESULT
319
 *   no return value, section object is updated
320
 ******/
321
function gen_associatedpanels_fields(&$section, $value1, $value2, $value3, $value4) {
322

    
323
	$group = new Form_Group('Associated Panels Show/Hide');
324

    
325
	$group->add(new Form_Checkbox(
326
		'dashboardavailablewidgetspanel',
327
		null,
328
		'Available Widgets',
329
		$value1
330
		))->setHelp('Show the Available Widgets panel on the Dashboard.');
331

    
332
	$group->add(new Form_Checkbox(
333
		'systemlogsfilterpanel',
334
		null,
335
		'Log Filter',
336
		$value2
337
	))->setHelp('Show the Log Filter panel in System Logs.');
338

    
339
	$group->add(new Form_Checkbox(
340
		'systemlogsmanagelogpanel',
341
		null,
342
		'Manage Log',
343
		$value3
344
	))->setHelp('Show the Manage Log panel in System Logs.');
345

    
346
	$group->add(new Form_Checkbox(
347
		'statusmonitoringsettingspanel',
348
		null,
349
		'Monitoring Settings',
350
		$value4
351
	))->setHelp('Show the Settings panel in Status Monitoring.');
352

    
353
	$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.');
354

    
355
	$section->add($group);
356
}
357

    
358
/****f* pfsense-utils/gen_webguileftcolumnhyper_field
359
 * NAME
360
 *   gen_webguileftcolumnhyper_field
361
 * INPUTS
362
 *   Pointer to section object
363
 *   Initial value for the field
364
 * RESULT
365
 *   no return value, section object is updated
366
 ******/
367
function gen_webguileftcolumnhyper_field(&$section, $value) {
368

    
369
	$section->addInput(new Form_Checkbox(
370
		'webguileftcolumnhyper',
371
		'Left Column Labels',
372
		'Active',
373
		$value
374
	))->setHelp('If selected, clicking a label in the left column will select/toggle the first item of the group.');
375
}
376

    
377
/****f* pfsense-utils/gen_disablealiaspopupdetail_field
378
 * NAME
379
 *   gen_disablealiaspopupdetail_field
380
 * INPUTS
381
 *   Pointer to section object
382
 *   Initial value for the field
383
 * RESULT
384
 *   no return value, section object is updated
385
 ******/
386
function gen_disablealiaspopupdetail_field(&$section, $value) {
387

    
388
	$section->addInput(new Form_Checkbox(
389
		'disablealiaspopupdetail',
390
		'Alias Popups',
391
		'Disable details in alias popups',
392
		$value
393
	))->setHelp('If selected, the details in alias popups will not be shown, just the alias description (e.g. in Firewall Rules).');
394
}
395

    
396
/****f* pfsense-utils/gen_pagenamefirst_field
397
 * NAME
398
 *   gen_pagenamefirst_field
399
 * INPUTS
400
 *   Pointer to section object
401
 *   Initial value for the field
402
 * RESULT
403
 *   no return value, section object is updated
404
 ******/
405
function gen_pagenamefirst_field(&$section, $value) {
406

    
407
	$section->addInput(new Form_Checkbox(
408
		'pagenamefirst',
409
		'Browser tab text',
410
		'Display page name first in browser tab',
411
		$value
412
	))->setHelp('When this is unchecked, the browser tab shows the host name followed '.
413
		'by the current page. Check this box to display the current page followed by the '.
414
		'host name.');
415
}
416

    
417
/****f* pfsense-utils/gen_user_settings_fields
418
 * NAME
419
 *   gen_user_settings_fields
420
 * INPUTS
421
 *   Pointer to section object
422
 *   Array of initial values for the fields
423
 * RESULT
424
 *   no return value, section object is updated
425
 ******/
426
function gen_user_settings_fields(&$section, $pconfig) {
427

    
428
	gen_webguicss_field($section, $pconfig['webguicss']);
429
	gen_webguifixedmenu_field($section, $pconfig['webguifixedmenu']);
430
	gen_webguihostnamemenu_field($section, $pconfig['webguihostnamemenu']);
431
	gen_dashboardcolumns_field($section, $pconfig['dashboardcolumns']);
432
	gen_interfacessort_field($section, $pconfig['interfacessort']);
433
	gen_associatedpanels_fields(
434
		$section,
435
		$pconfig['dashboardavailablewidgetspanel'],
436
		$pconfig['systemlogsfilterpanel'],
437
		$pconfig['systemlogsmanagelogpanel'],
438
		$pconfig['statusmonitoringsettingspanel']);
439
	gen_webguileftcolumnhyper_field($section, $pconfig['webguileftcolumnhyper']);
440
	gen_disablealiaspopupdetail_field($section, $pconfig['disablealiaspopupdetail']);
441
	gen_pagenamefirst_field($section, $pconfig['pagenamefirst']);
442
}
443

    
444
/****f* pfsense-utils/gen_requirestatefilter_field
445
 * NAME
446
 *   gen_requirestatefilter_field
447
 * INPUTS
448
 *   Pointer to section object
449
 *   Initial value for the field
450
 * RESULT
451
 *   no return value, section object is updated
452
 ******/
453
function gen_requirestatefilter_field(&$section, $value) {
454
	$section->addInput(new Form_Checkbox(
455
		'requirestatefilter',
456
		'Require State Filter',
457
		'Do not display state table without a filter',
458
		$value
459
	))->setHelp('By default, the entire state table is displayed when entering '.
460
		'Diagnostics > States. This option requires a filter to be entered '.
461
		'before the states are displayed. Useful for systems with large state tables.');
462
}
463

    
464
/****f* pfsense-utils/gen_created_updated_fields
465
 * NAME
466
 *   gen_created_updated_fields
467
 * INPUTS
468
 *   Pointer to form object
469
 *   Array of created time and username
470
 *   Array of updated time and username
471
 * RESULT
472
 *   no return value, section object is added to form if needed
473
 ******/
474
function gen_created_updated_fields(&$form, $created, $updated, $tracker = 0) {
475
	$has_created_time = (isset($created['time']) && isset($created['username']));
476
	$has_updated_time = (isset($updated['time']) && isset($updated['username']));
477

    
478
	if ($has_created_time || $has_updated_time) {
479
		$section = new Form_Section('Rule Information');
480

    
481
		if (!empty($tracker)) {
482
			$section->addInput(new Form_StaticText(
483
				'Tracking ID',
484
				htmlspecialchars($tracker)
485
			));
486
		}
487

    
488
		if ($has_created_time) {
489
			$section->addInput(new Form_StaticText(
490
				'Created',
491
				htmlspecialchars(sprintf(
492
					gettext('%1$s by %2$s'),
493
					date(gettext("n/j/y H:i:s"), $created['time']),
494
					$created['username']))
495
			));
496
		}
497

    
498
		if ($has_updated_time) {
499
			$section->addInput(new Form_StaticText(
500
				'Updated',
501
				htmlspecialchars(sprintf(
502
					gettext('%1$s by %2$s'),
503
					date(gettext("n/j/y H:i:s"), $updated['time']),
504
					$updated['username']))
505
			));
506
		}
507

    
508
		$form->add($section);
509
	}
510
}
511

    
512
function hardware_offloading_applyflags($iface) {
513
	global $config;
514

    
515
	$flags_on = 0;
516
	$flags_off = 0;
517
	$options = pfSense_get_interface_addresses($iface);
518

    
519
	if (isset($config['system']['disablechecksumoffloading'])) {
520
		if (isset($options['encaps']['txcsum'])) {
521
			$flags_off |= IFCAP_TXCSUM;
522
		}
523
		if (isset($options['encaps']['rxcsum'])) {
524
			$flags_off |= IFCAP_RXCSUM;
525
		}
526
		if (isset($options['encaps']['txcsum6'])) {
527
			$flags_off |= IFCAP_TXCSUM_IPV6;
528
		}
529
		if (isset($options['encaps']['rxcsum6'])) {
530
			$flags_off |= IFCAP_RXCSUM_IPV6;
531
		}
532
	} else {
533
		if (isset($options['caps']['txcsum'])) {
534
			$flags_on |= IFCAP_TXCSUM;
535
		}
536
		if (isset($options['caps']['rxcsum'])) {
537
			$flags_on |= IFCAP_RXCSUM;
538
		}
539
		if (isset($options['caps']['txcsum6'])) {
540
			$flags_on |= IFCAP_TXCSUM_IPV6;
541
		}
542
		if (isset($options['caps']['rxcsum6'])) {
543
			$flags_on |= IFCAP_RXCSUM_IPV6;
544
		}
545
	}
546

    
547
	if (isset($config['system']['disablesegmentationoffloading'])) {
548
		$flags_off |= IFCAP_TSO;
549
	} else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6'])) {
550
		$flags_on |= IFCAP_TSO;
551
	}
552

    
553
	if (isset($config['system']['disablelargereceiveoffloading'])) {
554
		$flags_off |= IFCAP_LRO;
555
	} else if (isset($options['caps']['lro'])) {
556
		$flags_on |= IFCAP_LRO;
557
	}
558

    
559
	pfSense_interface_capabilities($iface, -$flags_off);
560
	pfSense_interface_capabilities($iface, $flags_on);
561
}
562

    
563
/****f* pfsense-utils/enable_hardware_offloading
564
 * NAME
565
 *   enable_hardware_offloading - Enable a NIC's supported hardware features.
566
 * INPUTS
567
 *   $interface	- string containing the physical interface to work on.
568
 * RESULT
569
 *   null
570
 * NOTES
571
 *   This function only supports the fxp driver's loadable microcode.
572
 ******/
573
function enable_hardware_offloading($interface) {
574
	global $g, $config;
575

    
576
	$int = get_real_interface($interface);
577
	if (empty($int)) {
578
		return;
579
	}
580

    
581
	if (!isset($config['system']['do_not_use_nic_microcode'])) {
582
		/* translate wan, lan, opt -> real interface if needed */
583
		$int_family = preg_split("/[0-9]+/", $int);
584
		$supported_ints = array('fxp');
585
		if (in_array($int_family, $supported_ints)) {
586
			if (does_interface_exist($int)) {
587
				pfSense_interface_flags($int, IFF_LINK0);
588
			}
589
		}
590
	}
591

    
592
	/* This is mostly for vlans and ppp types */
593
	$realhwif = get_parent_interface($interface);
594
	if ($realhwif[0] == $int) {
595
		hardware_offloading_applyflags($int);
596
	} else {
597
		hardware_offloading_applyflags($realhwif[0]);
598
		hardware_offloading_applyflags($int);
599
	}
600
}
601

    
602
/****f* pfsense-utils/is_alias_inuse
603
 * NAME
604
 *   checks to see if an alias is currently in use by a rule
605
 * INPUTS
606
 *
607
 * RESULT
608
 *   true or false
609
 * NOTES
610
 *
611
 ******/
612
function is_alias_inuse($alias) {
613
	global $g, $config;
614

    
615
	if ($alias == "") {
616
		return false;
617
	}
618
	/* loop through firewall rules looking for alias in use */
619
	if (is_array($config['filter']['rule'])) {
620
		foreach ($config['filter']['rule'] as $rule) {
621
			if ($rule['source']['address']) {
622
				if ($rule['source']['address'] == $alias) {
623
					return true;
624
				}
625
			}
626
			if ($rule['destination']['address']) {
627
				if ($rule['destination']['address'] == $alias) {
628
					return true;
629
				}
630
			}
631
		}
632
	}
633
	/* loop through nat rules looking for alias in use */
634
	if (is_array($config['nat']['rule'])) {
635
		foreach ($config['nat']['rule'] as $rule) {
636
			if ($rule['target'] && $rule['target'] == $alias) {
637
				return true;
638
			}
639
			if ($rule['source']['address'] && $rule['source']['address'] == $alias) {
640
				return true;
641
			}
642
			if ($rule['destination']['address'] && $rule['destination']['address'] == $alias) {
643
				return true;
644
			}
645
		}
646
	}
647
	return false;
648
}
649

    
650
/****f* pfsense-utils/is_schedule_inuse
651
 * NAME
652
 *   checks to see if a schedule is currently in use by a rule
653
 * INPUTS
654
 *
655
 * RESULT
656
 *   true or false
657
 * NOTES
658
 *
659
 ******/
660
function is_schedule_inuse($schedule) {
661
	global $g, $config;
662

    
663
	if ($schedule == "") {
664
		return false;
665
	}
666
	/* loop through firewall rules looking for schedule in use */
667
	if (is_array($config['filter']['rule'])) {
668
		foreach ($config['filter']['rule'] as $rule) {
669
			if ($rule['sched'] == $schedule) {
670
				return true;
671
			}
672
		}
673
	}
674
	return false;
675
}
676

    
677
/****f* pfsense-utils/setup_microcode
678
 * NAME
679
 *   enumerates all interfaces and calls enable_hardware_offloading which
680
 *   enables a NIC's supported hardware features.
681
 * INPUTS
682
 *
683
 * RESULT
684
 *   null
685
 * NOTES
686
 *   This function only supports the fxp driver's loadable microcode.
687
 ******/
688
function setup_microcode() {
689

    
690
	/* if list */
691
	$iflist = get_configured_interface_list(true);
692
	foreach ($iflist as $if => $ifdescr) {
693
		enable_hardware_offloading($if);
694
	}
695
	unset($iflist);
696
}
697

    
698
/****f* pfsense-utils/get_carp_status
699
 * NAME
700
 *   get_carp_status - Return whether CARP is enabled or disabled.
701
 * RESULT
702
 *   boolean	- true if CARP is enabled, false if otherwise.
703
 ******/
704
function get_carp_status() {
705
	/* grab the current status of carp */
706
	$status = get_single_sysctl('net.inet.carp.allow');
707
	return (intval($status) > 0);
708
}
709

    
710
/*
711
 * convert_ip_to_network_format($ip, $subnet): converts an ip address to network form
712

    
713
 */
714
function convert_ip_to_network_format($ip, $subnet) {
715
	$ipsplit = explode('.', $ip);
716
	$string = $ipsplit[0] . "." . $ipsplit[1] . "." . $ipsplit[2] . ".0/" . $subnet;
717
	return $string;
718
}
719

    
720
/*
721
 * get_carp_interface_status($carpid): returns the status of a carp uniqid
722
 */
723
function get_carp_interface_status($carpid) {
724

    
725
	$carpiface = get_configured_vip_interface($carpid);
726
	if ($carpiface == NULL)
727
		return "";
728
	$interface = get_real_interface($carpiface);
729
	if ($interface == NULL)
730
		return "";
731
	$vip = get_configured_vip($carpid);
732
	if ($vip == NULL || !isset($vip['vhid']))
733
		return "";
734

    
735
	$vhid = $vip['vhid'];
736
	$carp_query = '';
737
	$_gb = exec("/sbin/ifconfig {$interface} | /usr/bin/grep \"carp:.* vhid {$vhid} \"", $carp_query);
738
	foreach ($carp_query as $int) {
739
		if (stripos($int, "MASTER"))
740
			return "MASTER";
741
		elseif (stripos($int, "BACKUP"))
742
			return "BACKUP";
743
		elseif (stripos($int, "INIT"))
744
			return "INIT";
745
	}
746

    
747
	return "";
748
}
749

    
750
/*
751
 * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
752
 */
753
function get_pfsync_interface_status($pfsyncinterface) {
754
	if (!does_interface_exist($pfsyncinterface)) {
755
		return;
756
	}
757

    
758
	return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
759
}
760

    
761
/*
762
 * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
763
 */
764
function add_rule_to_anchor($anchor, $rule, $label) {
765
	mwexec("echo " . escapeshellarg($rule) . " | /sbin/pfctl -a " . escapeshellarg($anchor) . ":" . escapeshellarg($label) . " -f -");
766
}
767

    
768
/*
769
 * remove_text_from_file
770
 * remove $text from file $file
771
 */
772
function remove_text_from_file($file, $text) {
773
	if (!file_exists($file) && !is_writable($file)) {
774
		return;
775
	}
776
	$filecontents = file_get_contents($file);
777
	$text = str_replace($text, "", $filecontents);
778
	@file_put_contents($file, $text);
779
}
780

    
781
/*
782
 *   after_sync_bump_adv_skew(): create skew values by 1S
783
 */
784
function after_sync_bump_adv_skew() {
785
	global $config, $g;
786
	$processed_skew = 1;
787
	$a_vip = &$config['virtualip']['vip'];
788
	foreach ($a_vip as $vipent) {
789
		if ($vipent['advskew'] <> "") {
790
			$processed_skew = 1;
791
			$vipent['advskew'] = $vipent['advskew']+1;
792
		}
793
	}
794
	if ($processed_skew == 1) {
795
		write_config(gettext("After synch increase advertising skew"));
796
	}
797
}
798

    
799
/*
800
 * get_filename_from_url($url): converts a url to its filename.
801
 */
802
function get_filename_from_url($url) {
803
	return basename($url);
804
}
805

    
806
/*
807
 *   get_dir: return an array of $dir
808
 */
809
function get_dir($dir) {
810
	$dir_array = array();
811
	$d = dir($dir);
812
	if (!is_object($d)) {
813
		return array();
814
	}
815
	while (false !== ($entry = $d->read())) {
816
		array_push($dir_array, $entry);
817
	}
818
	$d->close();
819
	return $dir_array;
820
}
821

    
822
/****f* pfsense-utils/WakeOnLan
823
 * NAME
824
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
825
 * RESULT
826
 *   true/false - true if the operation was successful
827
 ******/
828
function WakeOnLan($addr, $mac) {
829
	$addr_byte = explode(':', $mac);
830
	$hw_addr = '';
831

    
832
	for ($a = 0; $a < 6; $a++) {
833
		$hw_addr .= chr(hexdec($addr_byte[$a]));
834
	}
835

    
836
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
837

    
838
	for ($a = 1; $a <= 16; $a++) {
839
		$msg .= $hw_addr;
840
	}
841

    
842
	// send it to the broadcast address using UDP
843
	$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
844
	if ($s == false) {
845
		log_error(gettext("Error creating socket!"));
846
		log_error(sprintf(gettext("Error code is '%1\$s' - %2\$s"), socket_last_error($s), socket_strerror(socket_last_error($s))));
847
	} else {
848
		// setting a broadcast option to socket:
849
		$opt_ret = socket_set_option($s, 1, 6, TRUE);
850
		if ($opt_ret < 0) {
851
			log_error(sprintf(gettext("setsockopt() failed, error: %s"), strerror($opt_ret)));
852
		}
853
		$e = socket_sendto($s, $msg, strlen($msg), 0, $addr, 2050);
854
		socket_close($s);
855
		log_error(sprintf(gettext('Magic Packet sent (%1$s) to (%2$s) MAC=%3$s'), $e, $addr, $mac));
856
		return true;
857
	}
858

    
859
	return false;
860
}
861

    
862
/*
863
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
864
 *					 Useful for finding paths and stripping file extensions.
865
 */
866
function reverse_strrchr($haystack, $needle) {
867
	if (!is_string($haystack)) {
868
		return;
869
	}
870
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
871
}
872

    
873
/*
874
 *  backup_config_section($section): returns as an xml file string of
875
 *                                   the configuration section
876
 */
877
function backup_config_section($section_name) {
878
	global $config;
879
	$new_section = &$config[$section_name];
880
	/* generate configuration XML */
881
	$xmlconfig = dump_xml_config($new_section, $section_name);
882
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
883
	return $xmlconfig;
884
}
885

    
886
/*
887
 *  restore_config_section($section_name, new_contents): restore a configuration section,
888
 *                                                  and write the configuration out
889
 *                                                  to disk/cf.
890
 */
891
function restore_config_section($section_name, $new_contents) {
892
	global $config, $g;
893
	$fout = fopen("{$g['tmp_path']}/tmpxml", "w");
894
	fwrite($fout, $new_contents);
895
	fclose($fout);
896

    
897
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
898
	if ($xml['pfsense']) {
899
		$xml = $xml['pfsense'];
900
	}
901
	else if ($xml['m0n0wall']) {
902
		$xml = $xml['m0n0wall'];
903
	}
904
	if ($xml[$section_name]) {
905
		$section_xml = $xml[$section_name];
906
	} else {
907
		$section_xml = -1;
908
	}
909

    
910
	@unlink($g['tmp_path'] . "/tmpxml");
911
	if ($section_xml === -1) {
912
		return false;
913
	}
914
	$config[$section_name] = &$section_xml;
915
	if (file_exists("{$g['tmp_path']}/config.cache")) {
916
		unlink("{$g['tmp_path']}/config.cache");
917
	}
918
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
919
	disable_security_checks();
920
	return true;
921
}
922

    
923
/*
924
 *  merge_config_section($section_name, new_contents):   restore a configuration section,
925
 *                                                  and write the configuration out
926
 *                                                  to disk/cf.  But preserve the prior
927
 * 													structure if needed
928
 */
929
function merge_config_section($section_name, $new_contents) {
930
	global $config;
931
	$fname = get_tmp_filename();
932
	$fout = fopen($fname, "w");
933
	fwrite($fout, $new_contents);
934
	fclose($fout);
935
	$section_xml = parse_xml_config($fname, $section_name);
936
	$config[$section_name] = $section_xml;
937
	unlink($fname);
938
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
939
	disable_security_checks();
940
	return;
941
}
942

    
943
/*
944
 * rmdir_recursive($path, $follow_links=false)
945
 * Recursively remove a directory tree (rm -rf path)
946
 * This is for directories _only_
947
 */
948
function rmdir_recursive($path, $follow_links=false) {
949
	$to_do = glob($path);
950
	if (!is_array($to_do)) {
951
		$to_do = array($to_do);
952
	}
953
	foreach ($to_do as $workingdir) { // Handle wildcards by foreaching.
954
		if (file_exists($workingdir)) {
955
			if (is_dir($workingdir)) {
956
				$dir = opendir($workingdir);
957
				while ($entry = readdir($dir)) {
958
					if (is_file("$workingdir/$entry") || ((!$follow_links) && is_link("$workingdir/$entry"))) {
959
						unlink("$workingdir/$entry");
960
					} elseif (is_dir("$workingdir/$entry") && $entry != '.' && $entry != '..') {
961
						rmdir_recursive("$workingdir/$entry");
962
					}
963
				}
964
				closedir($dir);
965
				rmdir($workingdir);
966
			} elseif (is_file($workingdir)) {
967
				unlink($workingdir);
968
			}
969
		}
970
	}
971
	return;
972
}
973

    
974
/*
975
 * host_firmware_version(): Return the versions used in this install
976
 */
977
function host_firmware_version($tocheck = "") {
978
	global $g, $config;
979

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

    
982
	return array(
983
		"firmware" => array("version" => $g['product_version']),
984
		"kernel"   => array("version" => $os_version),
985
		"base"     => array("version" => $os_version),
986
		"platform" => $g['platform'],
987
		"config_version" => $config['version']
988
	);
989
}
990

    
991
function get_disk_info() {
992
	$diskout = "";
993
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
994
	return explode(' ', $diskout[0]);
995
}
996

    
997
/****f* pfsense-utils/strncpy
998
 * NAME
999
 *   strncpy - copy strings
1000
 * INPUTS
1001
 *   &$dst, $src, $length
1002
 * RESULT
1003
 *   none
1004
 ******/
1005
function strncpy(&$dst, $src, $length) {
1006
	if (strlen($src) > $length) {
1007
		$dst = substr($src, 0, $length);
1008
	} else {
1009
		$dst = $src;
1010
	}
1011
}
1012

    
1013
/****f* pfsense-utils/reload_interfaces_sync
1014
 * NAME
1015
 *   reload_interfaces - reload all interfaces
1016
 * INPUTS
1017
 *   none
1018
 * RESULT
1019
 *   none
1020
 ******/
1021
function reload_interfaces_sync() {
1022
	global $config, $g;
1023

    
1024
	if ($g['debug']) {
1025
		log_error(gettext("reload_interfaces_sync() is starting."));
1026
	}
1027

    
1028
	/* parse config.xml again */
1029
	$config = parse_config(true);
1030

    
1031
	/* enable routing */
1032
	system_routing_enable();
1033
	if ($g['debug']) {
1034
		log_error(gettext("Enabling system routing"));
1035
	}
1036

    
1037
	if ($g['debug']) {
1038
		log_error(gettext("Cleaning up Interfaces"));
1039
	}
1040

    
1041
	/* set up interfaces */
1042
	interfaces_configure();
1043
}
1044

    
1045
/****f* pfsense-utils/reload_all
1046
 * NAME
1047
 *   reload_all - triggers a reload of all settings
1048
 *   * INPUTS
1049
 *   none
1050
 * RESULT
1051
 *   none
1052
 ******/
1053
function reload_all() {
1054
	send_event("service reload all");
1055
}
1056

    
1057
/****f* pfsense-utils/reload_interfaces
1058
 * NAME
1059
 *   reload_interfaces - triggers a reload of all interfaces
1060
 * INPUTS
1061
 *   none
1062
 * RESULT
1063
 *   none
1064
 ******/
1065
function reload_interfaces() {
1066
	send_event("interface all reload");
1067
}
1068

    
1069
/****f* pfsense-utils/reload_all_sync
1070
 * NAME
1071
 *   reload_all - reload all settings
1072
 *   * INPUTS
1073
 *   none
1074
 * RESULT
1075
 *   none
1076
 ******/
1077
function reload_all_sync() {
1078
	global $config, $g;
1079

    
1080
	/* parse config.xml again */
1081
	$config = parse_config(true);
1082

    
1083
	/* set up our timezone */
1084
	system_timezone_configure();
1085

    
1086
	/* set up our hostname */
1087
	system_hostname_configure();
1088

    
1089
	/* make hosts file */
1090
	system_hosts_generate();
1091

    
1092
	/* generate resolv.conf */
1093
	system_resolvconf_generate();
1094

    
1095
	/* enable routing */
1096
	system_routing_enable();
1097

    
1098
	/* set up interfaces */
1099
	interfaces_configure();
1100

    
1101
	/* start dyndns service */
1102
	services_dyndns_configure();
1103

    
1104
	/* configure cron service */
1105
	configure_cron();
1106

    
1107
	/* start the NTP client */
1108
	system_ntp_configure();
1109

    
1110
	/* sync pw database */
1111
	unlink_if_exists("/etc/spwd.db.tmp");
1112
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
1113

    
1114
	/* restart sshd */
1115
	send_event("service restart sshd");
1116

    
1117
	/* restart webConfigurator if needed */
1118
	send_event("service restart webgui");
1119
}
1120

    
1121
function load_loader_conf($loader_conf = NULL, $local = false) {
1122

    
1123
	if ($loader_conf == NULL) {
1124
		return (NULL);
1125
	}
1126
	if (file_exists($loader_conf)) {
1127
		$input = file_get_contents($loader_conf);
1128
	} else {
1129
		$input = "";
1130
	}
1131

    
1132
	$input_split = explode("\n", $input);
1133

    
1134
	/*
1135
	 * Loop through and only add lines that are not empty and not
1136
	 * managed by us.
1137
	 */
1138
	$data = array();
1139
	/* These values should be removed from loader.conf and loader.conf.local
1140
	 * As they will be replaced when necessary. */
1141
	$remove = array("hw.usb.no_pf", "hint.mdio.0.at", "hint.e6000sw.0",
1142
	    "vm.pmap.pti");
1143
	if (!$local) {
1144
		/* These values should only be filtered in loader.conf, not .local */
1145
		$remove = array_merge($remove,
1146
		    array("autoboot_delay", "console", "comconsole_speed",
1147
		    "boot_multicons", "boot_serial", "hint.uart.0.flags",
1148
		    "hint.uart.1.flags"));
1149
	}
1150
	foreach ($input_split as $line) {
1151
		if (empty($line)) {
1152
			continue;
1153
		}
1154
		list($name, $value) = explode('=', $line, 2);
1155
		if (!in_array(trim($name), $remove)) {
1156
			$data[] = $line;
1157
		}
1158
	}
1159

    
1160
	return ($data);
1161
}
1162

    
1163
function setup_loader_settings($path = "", $upgrade = false) {
1164
	global $g, $config;
1165

    
1166
	$boot_config_file = "{$path}/boot.config";
1167
	$loader_conf_file = "{$path}/boot/loader.conf";
1168

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

    
1171
	$vga_only = false;
1172
	$hdmi_only = false;
1173
	$serial_only = false;
1174
	$specific_platform = system_identify_specific_platform();
1175
	if ($specific_platform['name'] == 'XG-1540') {
1176
		$vga_only = true;
1177
	} elseif ($specific_platform['name'] == 'Turbot Dual-E') {
1178
		$hdmi_only = true;
1179
	} elseif ($specific_platform['name'] == 'RCC-VE' ||
1180
	    $specific_platform['name'] == 'RCC' ||
1181
	    $specific_platform['name'] == 'SG-2220' ||
1182
	    $specific_platform['name'] == 'apu2') {
1183
		$serial_only = true;
1184
	}
1185

    
1186
	/* Serial console - write out /boot.config */
1187
	if (file_exists($boot_config_file)) {
1188
		$boot_config = file_get_contents($boot_config_file);
1189
	} else {
1190
		$boot_config = "";
1191
	}
1192
	$boot_config_split = explode("\n", $boot_config);
1193
	$data = array();
1194
	foreach ($boot_config_split as $bcs) {
1195
		/* Ignore -D and -h lines now */
1196
		if (!empty($bcs) && !stristr($bcs, "-D") &&
1197
		    !stristr($bcs, "-h")) {
1198
			$data[] = $bcs;
1199
		}
1200
	}
1201
	if ($serial_only === true) {
1202
		$data[] = "-S{$serialspeed} -h";
1203
	} elseif (is_serial_enabled()) {
1204
		$data[] = "-S{$serialspeed} -D";
1205
	}
1206

    
1207
	if (empty($data)) {
1208
		@unlink($boot_conf_file);
1209
	} else {
1210
		safe_write_file($boot_config_file, $data);
1211
	}
1212
	unset($data, $boot_config, $boot_config_file, $boot_config_split);
1213

    
1214
	/* Serial console - write out /boot/loader.conf */
1215
	if ($upgrade) {
1216
		system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1217
	}
1218

    
1219
	$data = load_loader_conf($loader_conf_file);
1220
	if ($serial_only === true) {
1221
		$data[] = 'boot_serial="YES"';
1222
		$data[] = 'console="comconsole"';
1223
		$data[] = 'comconsole_speed="' . $serialspeed . '"';
1224
	} elseif ($vga_only === true) {
1225
		$data[] = 'console="vidconsole"';
1226
	} elseif (is_serial_enabled()) {
1227
		$data[] = 'boot_multicons="YES"';
1228
		$data[] = 'boot_serial="YES"';
1229
		$primaryconsole = isset($g['primaryconsole_force']) ?
1230
		    $g['primaryconsole_force'] :
1231
		    $config['system']['primaryconsole'];
1232
		switch ($primaryconsole) {
1233
			case "video":
1234
				$data[] = 'console="vidconsole,comconsole"';
1235
				break;
1236
			case "serial":
1237
			default:
1238
				$data[] = 'console="comconsole,vidconsole"';
1239
		}
1240
		$data[] = 'comconsole_speed="' . $serialspeed . '"';
1241
	}
1242

    
1243
	if ($specific_platform['name'] == 'RCC-VE' ||
1244
	    $specific_platform['name'] == 'RCC' ||
1245
	    $specific_platform['name'] == 'SG-2220') {
1246
		$data[] = 'comconsole_port="0x2F8"';
1247
		$data[] = 'hint.uart.0.flags="0x00"';
1248
		$data[] = 'hint.uart.1.flags="0x10"';
1249
	}
1250
	$data[] = 'autoboot_delay="3"';
1251
	$data[] = 'hw.usb.no_pf="1"';
1252
	if (isset($config['system']['pti_disabled'])) {
1253
		$data[] = 'vm.pmap.pti="0"';
1254
	}
1255

    
1256
	safe_write_file($loader_conf_file, $data);
1257

    
1258
	/* Filter loader.conf.local to avoid duplicate settings. */
1259
	$loader_conf_file = "{$path}/boot/loader.conf.local";
1260
	$data = load_loader_conf($loader_conf_file, true);
1261
	if (empty($data)) {
1262
		@unlink($loader_conf_file);
1263
	} else {
1264
		safe_write_file($loader_conf_file, $data);
1265
	}
1266

    
1267
}
1268

    
1269
function setup_serial_port($when = "save", $path = "") {
1270
	global $config;
1271
	$ttys_file = "{$path}/etc/ttys";
1272

    
1273
	/* Update the loader settings. */
1274
	setup_loader_settings($path, ($when == "upgrade"));
1275

    
1276
	$ttys = file_get_contents($ttys_file);
1277
	$ttys_split = explode("\n", $ttys);
1278

    
1279
	$data = array();
1280

    
1281
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1282

    
1283
	if (isset($config['system']['disableconsolemenu'])) {
1284
		$console_type = 'Pc';
1285
		$serial_type = '3wire';
1286
	} else {
1287
		$console_type = 'al.Pc';
1288
		$serial_type = 'al.3wire';
1289
	}
1290

    
1291
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1292
	$ttyv0_line =
1293
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\txterm\ton\tsecure";
1294
	$ttyu_line =
1295
	    "\"/usr/libexec/getty {$serial_type}\"\tvt100\t{$on_off}\tsecure";
1296

    
1297
	$found = array();
1298

    
1299
	foreach ($ttys_split as $tty) {
1300
		/* Ignore blank lines */
1301
		if (empty($tty)) {
1302
			continue;
1303
		}
1304

    
1305
		if (stristr($tty, "ttyv0")) {
1306
			$found['ttyv0'] = 1;
1307
			$data[] = $ttyv0_line;
1308
		} elseif (stristr($tty, "ttyu")) {
1309
			$ttyn = substr($tty, 0, 5);
1310
			$found[$ttyn] = 1;
1311
			$data[] = "{$ttyn}\t{$ttyu_line}";
1312
		} elseif (substr($tty, 0, 7) == 'console') {
1313
			$found['console'] = 1;
1314
			$data[] = $tty;
1315
		} else {
1316
			$data[] = $tty;
1317
		}
1318
	}
1319
	unset($on_off, $console_type, $serial_type);
1320

    
1321
	/* Detect missing main lines on original file and try to rebuild it */
1322
	$items = array(
1323
		'console',
1324
		'ttyv0',
1325
		'ttyu0',
1326
		'ttyu1',
1327
		'ttyu2',
1328
		'ttyu3'
1329
	);
1330

    
1331
	foreach ($items as $item) {
1332
		if (isset($found[$item])) {
1333
			continue;
1334
		}
1335

    
1336
		if ($item == 'console') {
1337
			$data[] = $console_line;
1338
		} elseif ($item == 'ttyv0') {
1339
			$data[] = $ttyv0_line;
1340
		} else {
1341
			$data[] = "{$item}\t{$ttyu_line}";
1342
		}
1343
	}
1344

    
1345
	safe_write_file($ttys_file, $data);
1346

    
1347
	unset($ttys, $ttys_file, $ttys_split, $data);
1348

    
1349
	if ($when != "upgrade") {
1350
		reload_ttys();
1351
	}
1352

    
1353
	return;
1354
}
1355

    
1356
function is_serial_enabled() {
1357
	global $g, $config;
1358

    
1359
	if (!isset($g['enableserial_force']) &&
1360
	    !isset($config['system']['enableserial'])) {
1361
		return false;
1362
	}
1363

    
1364
	return true;
1365
}
1366

    
1367
function reload_ttys() {
1368
	// Send a HUP signal to init will make it reload /etc/ttys
1369
	posix_kill(1, SIGHUP);
1370
}
1371

    
1372
function print_value_list($list, $count = 10, $separator = ",") {
1373
	$list = implode($separator, array_slice($list, 0, $count));
1374
	if (count($list) < $count) {
1375
		$list .= ".";
1376
	} else {
1377
		$list .= "...";
1378
	}
1379
	return $list;
1380
}
1381

    
1382
/* DHCP enabled on any interfaces? */
1383
function is_dhcp_server_enabled() {
1384
	global $config;
1385

    
1386
	if (!is_array($config['dhcpd'])) {
1387
		return false;
1388
	}
1389

    
1390
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1391
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1392
			return true;
1393
		}
1394
	}
1395

    
1396
	return false;
1397
}
1398

    
1399
/* DHCP enabled on any interfaces? */
1400
function is_dhcpv6_server_enabled() {
1401
	global $config;
1402

    
1403
	if (is_array($config['interfaces'])) {
1404
		foreach ($config['interfaces'] as $ifcfg) {
1405
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1406
				return true;
1407
			}
1408
		}
1409
	}
1410

    
1411
	if (!is_array($config['dhcpdv6'])) {
1412
		return false;
1413
	}
1414

    
1415
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1416
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1417
			return true;
1418
		}
1419
	}
1420

    
1421
	return false;
1422
}
1423

    
1424
/* radvd enabled on any interfaces? */
1425
function is_radvd_enabled() {
1426
	global $config;
1427

    
1428
	if (!is_array($config['dhcpdv6'])) {
1429
		$config['dhcpdv6'] = array();
1430
	}
1431

    
1432
	$dhcpdv6cfg = $config['dhcpdv6'];
1433
	$Iflist = get_configured_interface_list();
1434

    
1435
	/* handle manually configured DHCP6 server settings first */
1436
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1437
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1438
			continue;
1439
		}
1440

    
1441
		if (!isset($dhcpv6ifconf['ramode'])) {
1442
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1443
		}
1444

    
1445
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1446
			continue;
1447
		}
1448

    
1449
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1450
		if (!is_ipaddrv6($ifcfgipv6)) {
1451
			continue;
1452
		}
1453

    
1454
		return true;
1455
	}
1456

    
1457
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1458
	foreach ($Iflist as $if => $ifdescr) {
1459
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1460
			continue;
1461
		}
1462
		if (!isset($config['interfaces'][$if]['enable'])) {
1463
			continue;
1464
		}
1465

    
1466
		$ifcfgipv6 = get_interface_ipv6($if);
1467
		if (!is_ipaddrv6($ifcfgipv6)) {
1468
			continue;
1469
		}
1470

    
1471
		$ifcfgsnv6 = get_interface_subnetv6($if);
1472
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1473

    
1474
		if (!is_ipaddrv6($subnetv6)) {
1475
			continue;
1476
		}
1477

    
1478
		return true;
1479
	}
1480

    
1481
	return false;
1482
}
1483

    
1484
/* Any PPPoE servers enabled? */
1485
function is_pppoe_server_enabled() {
1486
	global $config;
1487

    
1488
	$pppoeenable = false;
1489

    
1490
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1491
		return false;
1492
	}
1493

    
1494
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1495
		if ($pppoes['mode'] == 'server') {
1496
			$pppoeenable = true;
1497
		}
1498
	}
1499

    
1500
	return $pppoeenable;
1501
}
1502

    
1503
/* Optional arg forces hh:mm:ss without days */
1504
function convert_seconds_to_dhms($sec, $showhoursonly = false) {
1505
	if (!is_numericint($sec)) {
1506
		return '-';
1507
	}
1508
	// FIXME: When we move to PHP 7 we can use "intdiv($sec % X, Y)" etc
1509
	list($d, $h, $m, $s) = array(	(int)($showhoursonly ? 0 : $sec/86400),
1510
					(int)(($showhoursonly ? $sec : $sec % 86400)/3600),
1511
					(int)(($sec % 3600)/60),
1512
					$sec % 60
1513
				);
1514
	return ($d > 0 ? $d . 'd ' : '') . sprintf('%02d:%02d:%02d', $h, $m, $s);
1515
}
1516

    
1517
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1518

    
1519
function get_ppp_uptime($port) {
1520
	if (file_exists("/conf/{$port}.log")) {
1521
		$saved_time = file_get_contents("/conf/{$port}.log");
1522
		$uptime_data = explode("\n", $saved_time);
1523
		$sec = 0;
1524
		foreach ($uptime_data as $upt) {
1525
			$sec += substr($upt, 1 + strpos($upt, " "));
1526
		}
1527
		return convert_seconds_to_dhms($sec);
1528
	} else {
1529
		$total_time = gettext("No history data found!");
1530
		return $total_time;
1531
	}
1532
}
1533

    
1534
//returns interface information
1535
function get_interface_info($ifdescr) {
1536
	global $config, $g;
1537

    
1538
	$ifinfo = array();
1539
	if (empty($config['interfaces'][$ifdescr])) {
1540
		return;
1541
	}
1542
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1543
	$ifinfo['enable'] = isset($config['interfaces'][$ifdescr]['enable']);
1544
	$ifinfo['if'] = get_real_interface($ifdescr);
1545

    
1546
	$chkif = $ifinfo['if'];
1547
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1548
	$ifinfo['status'] = $ifinfotmp['status'];
1549
	if (empty($ifinfo['status'])) {
1550
		$ifinfo['status'] = "down";
1551
	}
1552
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1553
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1554
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1555
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1556
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1557
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1558
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1559
	if (isset($ifinfotmp['link0'])) {
1560
		$link0 = "down";
1561
	}
1562
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1563
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1564
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1565
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1566
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1567
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1568

    
1569
	/* Use pfctl for non wrapping 64 bit counters */
1570
	/* Pass */
1571
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1572
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1573
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1574
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1575
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1576
	$in4_pass = $pf_in4_pass[5];
1577
	$out4_pass = $pf_out4_pass[5];
1578
	$in4_pass_packets = $pf_in4_pass[3];
1579
	$out4_pass_packets = $pf_out4_pass[3];
1580
	$in6_pass = $pf_in6_pass[5];
1581
	$out6_pass = $pf_out6_pass[5];
1582
	$in6_pass_packets = $pf_in6_pass[3];
1583
	$out6_pass_packets = $pf_out6_pass[3];
1584
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1585
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1586
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1587
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1588

    
1589
	/* Block */
1590
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1591
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1592
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1593
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1594
	$in4_block = $pf_in4_block[5];
1595
	$out4_block = $pf_out4_block[5];
1596
	$in4_block_packets = $pf_in4_block[3];
1597
	$out4_block_packets = $pf_out4_block[3];
1598
	$in6_block = $pf_in6_block[5];
1599
	$out6_block = $pf_out6_block[5];
1600
	$in6_block_packets = $pf_in6_block[3];
1601
	$out6_block_packets = $pf_out6_block[3];
1602
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1603
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1604
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1605
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1606

    
1607
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1608
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1609
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1610
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1611

    
1612
	$ifconfiginfo = "";
1613
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1614
	switch ($link_type) {
1615
		/* DHCP? -> see if dhclient is up */
1616
		case "dhcp":
1617
			/* see if dhclient is up */
1618
			if (find_dhclient_process($ifinfo['if']) != 0) {
1619
				$ifinfo['dhcplink'] = "up";
1620
			} else {
1621
				$ifinfo['dhcplink'] = "down";
1622
			}
1623

    
1624
			break;
1625
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1626
		case "pppoe":
1627
		case "pptp":
1628
		case "l2tp":
1629
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1630
				/* get PPPoE link status for dial on demand */
1631
				$ifinfo["{$link_type}link"] = "up";
1632
			} else {
1633
				$ifinfo["{$link_type}link"] = "down";
1634
			}
1635

    
1636
			break;
1637
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1638
		case "ppp":
1639
			if ($ifinfo['status'] == "up") {
1640
				$ifinfo['ppplink'] = "up";
1641
			} else {
1642
				$ifinfo['ppplink'] = "down" ;
1643
			}
1644

    
1645
			if (empty($ifinfo['status'])) {
1646
				$ifinfo['status'] = "down";
1647
			}
1648

    
1649
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1650
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1651
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1652
						break;
1653
					}
1654
				}
1655
			}
1656
			$dev = $ppp['ports'];
1657
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1658
				break;
1659
			}
1660
			if (!file_exists($dev)) {
1661
				$ifinfo['nodevice'] = 1;
1662
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1663
			}
1664

    
1665
			$usbmodemoutput = array();
1666
			exec("/usr/sbin/usbconfig", $usbmodemoutput);
1667
			$mondev = "{$g['tmp_path']}/3gstats.{$ifdescr}";
1668
			if (file_exists($mondev)) {
1669
				$cellstats = file($mondev);
1670
				/* skip header */
1671
				$a_cellstats = explode(",", $cellstats[1]);
1672
				if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1673
					$ifinfo['cell_rssi'] = huawei_rssi_to_string($a_cellstats[1]);
1674
					$ifinfo['cell_mode'] = huawei_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1675
					$ifinfo['cell_simstate'] = huawei_simstate_to_string($a_cellstats[10]);
1676
					$ifinfo['cell_service'] = huawei_service_to_string(trim($a_cellstats[11]));
1677
				}
1678
				if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1679
					$ifinfo['cell_rssi'] = zte_rssi_to_string($a_cellstats[1]);
1680
					$ifinfo['cell_mode'] = zte_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1681
					$ifinfo['cell_simstate'] = zte_simstate_to_string($a_cellstats[10]);
1682
					$ifinfo['cell_service'] = zte_service_to_string(trim($a_cellstats[11]));
1683
				}
1684
				$ifinfo['cell_upstream'] = $a_cellstats[4];
1685
				$ifinfo['cell_downstream'] = trim($a_cellstats[5]);
1686
				$ifinfo['cell_sent'] = $a_cellstats[6];
1687
				$ifinfo['cell_received'] = trim($a_cellstats[7]);
1688
				$ifinfo['cell_bwupstream'] = $a_cellstats[8];
1689
				$ifinfo['cell_bwdownstream'] = trim($a_cellstats[9]);
1690
			}
1691
			// Calculate cumulative uptime for PPP link. Useful for connections that have per minute/hour contracts so you don't go over!
1692
			if (isset($ppp['uptime'])) {
1693
				$ifinfo['ppp_uptime_accumulated'] = "(".get_ppp_uptime($ifinfo['if']).")";
1694
			}
1695
			break;
1696
		default:
1697
			break;
1698
	}
1699

    
1700
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1701
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1702
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1703
	}
1704

    
1705
	if ($ifinfo['status'] == "up") {
1706
		/* try to determine media with ifconfig */
1707
		unset($ifconfiginfo);
1708
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1709
		$wifconfiginfo = array();
1710
		if (is_interface_wireless($ifdescr)) {
1711
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1712
			array_shift($wifconfiginfo);
1713
		}
1714
		$matches = "";
1715
		foreach ($ifconfiginfo as $ici) {
1716

    
1717
			/* don't list media/speed for wireless cards, as it always
1718
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1719
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1720
				$ifinfo['media'] = $matches[1];
1721
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1722
				$ifinfo['media'] = $matches[1];
1723
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1724
				$ifinfo['media'] = $matches[1];
1725
			}
1726

    
1727
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1728
				if ($matches[1] != "active") {
1729
					$ifinfo['status'] = $matches[1];
1730
				}
1731
				if ($ifinfo['status'] == gettext("running")) {
1732
					$ifinfo['status'] = gettext("up");
1733
				}
1734
			}
1735
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1736
				$ifinfo['channel'] = $matches[1];
1737
			}
1738
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1739
				if ($matches[1][0] == '"') {
1740
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1741
				}
1742
				else {
1743
					$ifinfo['ssid'] = $matches[1];
1744
				}
1745
			}
1746
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1747
				$ifinfo['laggproto'] = $matches[1];
1748
			}
1749
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1750
				$ifinfo['laggport'][] = $matches[1];
1751
			}
1752
		}
1753
		foreach ($wifconfiginfo as $ici) {
1754
			$elements = preg_split("/[ ]+/i", $ici);
1755
			if ($elements[0] != "") {
1756
				$ifinfo['bssid'] = $elements[0];
1757
			}
1758
			if ($elements[3] != "") {
1759
				$ifinfo['rate'] = $elements[3];
1760
			}
1761
			if ($elements[4] != "") {
1762
				$ifinfo['rssi'] = $elements[4];
1763
			}
1764
		}
1765
		/* lookup the gateway */
1766
		if (interface_has_gateway($ifdescr)) {
1767
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1768
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1769
		}
1770
	}
1771

    
1772
	$bridge = "";
1773
	$bridge = link_interface_to_bridge($ifdescr);
1774
	if ($bridge) {
1775
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1776
		if (stristr($bridge_text, "blocking") <> false) {
1777
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1778
			$ifinfo['bridgeint'] = $bridge;
1779
		} else if (stristr($bridge_text, "learning") <> false) {
1780
			$ifinfo['bridge'] = gettext("learning");
1781
			$ifinfo['bridgeint'] = $bridge;
1782
		} else if (stristr($bridge_text, "forwarding") <> false) {
1783
			$ifinfo['bridge'] = gettext("forwarding");
1784
			$ifinfo['bridgeint'] = $bridge;
1785
		}
1786
	}
1787

    
1788
	return $ifinfo;
1789
}
1790

    
1791
//returns cpu speed of processor. Good for determining capabilities of machine
1792
function get_cpu_speed() {
1793
	return get_single_sysctl("hw.clockrate");
1794
}
1795

    
1796
function get_uptime_sec() {
1797
	$boottime = "";
1798
	$matches = "";
1799
	$boottime = get_single_sysctl("kern.boottime");
1800
	preg_match("/sec = (\d+)/", $boottime, $matches);
1801
	$boottime = $matches[1];
1802
	if (intval($boottime) == 0) {
1803
		return 0;
1804
	}
1805

    
1806
	$uptime = time() - $boottime;
1807
	return $uptime;
1808
}
1809

    
1810
function add_hostname_to_watch($hostname) {
1811
	if (!is_dir("/var/db/dnscache")) {
1812
		mkdir("/var/db/dnscache");
1813
	}
1814
	$result = array();
1815
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1816
		$domrecords = array();
1817
		$domips = array();
1818
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1819
		if ($rethost == 0) {
1820
			foreach ($domrecords as $domr) {
1821
				$doml = explode(" ", $domr);
1822
				$domip = $doml[3];
1823
				/* fill array with domain ip addresses */
1824
				if (is_ipaddr($domip)) {
1825
					$domips[] = $domip;
1826
				}
1827
			}
1828
		}
1829
		sort($domips);
1830
		$contents = "";
1831
		if (!empty($domips)) {
1832
			foreach ($domips as $ip) {
1833
				$contents .= "$ip\n";
1834
			}
1835
		}
1836
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1837
		/* Remove empty elements */
1838
		$result = array_filter(explode("\n", $contents), 'strlen');
1839
	}
1840
	return $result;
1841
}
1842

    
1843
function is_fqdn($fqdn) {
1844
	$hostname = false;
1845
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1846
		$hostname = true;
1847
	}
1848
	if (preg_match("/\.\./", $fqdn)) {
1849
		$hostname = false;
1850
	}
1851
	if (preg_match("/^\./i", $fqdn)) {
1852
		$hostname = false;
1853
	}
1854
	if (preg_match("/\//i", $fqdn)) {
1855
		$hostname = false;
1856
	}
1857
	return($hostname);
1858
}
1859

    
1860
function pfsense_default_state_size() {
1861
	/* get system memory amount */
1862
	$memory = get_memory();
1863
	$physmem = $memory[0];
1864
	/* Be cautious and only allocate 10% of system memory to the state table */
1865
	$max_states = (int) ($physmem/10)*1000;
1866
	return $max_states;
1867
}
1868

    
1869
function pfsense_default_tables_size() {
1870
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1871
	return $current;
1872
}
1873

    
1874
function pfsense_default_table_entries_size() {
1875
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1876
	return (trim($current));
1877
}
1878

    
1879
/* Compare the current hostname DNS to the DNS cache we made
1880
 * if it has changed we return the old records
1881
 * if no change we return false */
1882
function compare_hostname_to_dnscache($hostname) {
1883
	if (!is_dir("/var/db/dnscache")) {
1884
		mkdir("/var/db/dnscache");
1885
	}
1886
	$hostname = trim($hostname);
1887
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1888
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1889
	} else {
1890
		$oldcontents = "";
1891
	}
1892
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1893
		$domrecords = array();
1894
		$domips = array();
1895
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1896
		if ($rethost == 0) {
1897
			foreach ($domrecords as $domr) {
1898
				$doml = explode(" ", $domr);
1899
				$domip = $doml[3];
1900
				/* fill array with domain ip addresses */
1901
				if (is_ipaddr($domip)) {
1902
					$domips[] = $domip;
1903
				}
1904
			}
1905
		}
1906
		sort($domips);
1907
		$contents = "";
1908
		if (!empty($domips)) {
1909
			foreach ($domips as $ip) {
1910
				$contents .= "$ip\n";
1911
			}
1912
		}
1913
	}
1914

    
1915
	if (trim($oldcontents) != trim($contents)) {
1916
		if ($g['debug']) {
1917
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1918
		}
1919
		return ($oldcontents);
1920
	} else {
1921
		return false;
1922
	}
1923
}
1924

    
1925
/*
1926
 * load_crypto() - Load crypto modules if enabled in config.
1927
 */
1928
function load_crypto() {
1929
	global $config, $g;
1930
	$crypto_modules = array('aesni', 'cryptodev');
1931

    
1932
	$enabled_modules = explode('_', $config['system']['crypto_hardware']);
1933

    
1934
	foreach ($enabled_modules as $enmod) {
1935
		if (empty($enmod) || !in_array($enmod, $crypto_modules)) {
1936
			continue;
1937
		}
1938
		if (!is_module_loaded($enmod)) {
1939
			log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $enmod));
1940
			mwexec("/sbin/kldload " . escapeshellarg($enmod));
1941
		}
1942
	}
1943
}
1944

    
1945
/*
1946
 * load_thermal_hardware() - Load temperature monitor kernel module
1947
 */
1948
function load_thermal_hardware() {
1949
	global $config, $g;
1950
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1951

    
1952
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1953
		return false;
1954
	}
1955

    
1956
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1957
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1958
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1959
	}
1960
}
1961

    
1962
/****f* pfsense-utils/isvm
1963
 * NAME
1964
 *   isvm
1965
 * INPUTS
1966
 *	none
1967
 * RESULT
1968
 *   returns true if machine is running under a virtual environment
1969
 ******/
1970
function isvm() {
1971
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
1972
	$_gb = exec('/bin/kenv -q smbios.system.product 2>/dev/null', $output, $rc);
1973

    
1974
	if ($rc != 0 || !isset($output[0])) {
1975
		return false;
1976
	}
1977

    
1978
	foreach ($virtualenvs as $virtualenv) {
1979
		if (stripos($output[0], $virtualenv) !== false) {
1980
			return true;
1981
		}
1982
	}
1983

    
1984
	return false;
1985
}
1986

    
1987
function get_freebsd_version() {
1988
	$version = explode(".", php_uname("r"));
1989
	return $version[0];
1990
}
1991

    
1992
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
1993
	global $config, $g;
1994

    
1995
	$fp = fopen($destination, "wb");
1996

    
1997
	if (!$fp) {
1998
		return false;
1999
	}
2000

    
2001
	$ch = curl_init();
2002
	curl_setopt($ch, CURLOPT_URL, $url);
2003
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
2004
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2005
	curl_setopt($ch, CURLOPT_FILE, $fp);
2006
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2007
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2008
	curl_setopt($ch, CURLOPT_HEADER, false);
2009
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2010
	if (!isset($config['system']['do_not_send_uniqueid'])) {
2011
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
2012
	} else {
2013
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2014
	}
2015

    
2016
	if (!empty($config['system']['proxyurl'])) {
2017
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2018
		if (!empty($config['system']['proxyport'])) {
2019
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2020
		}
2021
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2022
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2023
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2024
		}
2025
	}
2026

    
2027
	@curl_exec($ch);
2028
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2029
	fclose($fp);
2030
	curl_close($ch);
2031
	if ($http_code == 200) {
2032
		return true;
2033
	} else {
2034
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2035
		unlink_if_exists($destination);
2036
		return false;
2037
	}
2038
}
2039

    
2040
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
2041
	global $config, $g;
2042
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
2043
	$file_size = 1;
2044
	$downloaded = 1;
2045
	$first_progress_update = TRUE;
2046
	/* open destination file */
2047
	$fout = fopen($destination, "wb");
2048

    
2049
	if (!$fout) {
2050
		return false;
2051
	}
2052
	/*
2053
	 *      Originally by Author: Keyvan Minoukadeh
2054
	 *      Modified by Scott Ullrich to return Content-Length size
2055
	 */
2056
	$ch = curl_init();
2057
	curl_setopt($ch, CURLOPT_URL, $url);
2058
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
2059
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2060
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
2061
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2062
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
2063
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
2064
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2065
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2066
	if (!isset($config['system']['do_not_send_uniqueid'])) {
2067
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
2068
	} else {
2069
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2070
	}
2071

    
2072
	if (!empty($config['system']['proxyurl'])) {
2073
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2074
		if (!empty($config['system']['proxyport'])) {
2075
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2076
		}
2077
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2078
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2079
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2080
		}
2081
	}
2082

    
2083
	@curl_exec($ch);
2084
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2085
	fclose($fout);
2086
	curl_close($ch);
2087
	if ($http_code == 200) {
2088
		return true;
2089
	} else {
2090
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2091
		unlink_if_exists($destination);
2092
		return false;
2093
	}
2094
}
2095

    
2096
function read_header($ch, $string) {
2097
	global $file_size, $fout;
2098
	$length = strlen($string);
2099
	$regs = "";
2100
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
2101
	if ($regs[2] <> "") {
2102
		$file_size = intval($regs[2]);
2103
	}
2104
	ob_flush();
2105
	return $length;
2106
}
2107

    
2108
function read_body($ch, $string) {
2109
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
2110
	global $pkg_interface;
2111
	$length = strlen($string);
2112
	$downloaded += intval($length);
2113
	if ($file_size > 0) {
2114
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
2115
		$downloadProgress = 100 - $downloadProgress;
2116
	} else {
2117
		$downloadProgress = 0;
2118
	}
2119
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
2120
		if ($sendto == "status") {
2121
			if ($pkg_interface == "console") {
2122
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2123
					$tostatus = $static_status . $downloadProgress . "%";
2124
					if ($downloadProgress == 100) {
2125
						$tostatus = $tostatus . "\r";
2126
					}
2127
					update_status($tostatus);
2128
				}
2129
			} else {
2130
				$tostatus = $static_status . $downloadProgress . "%";
2131
				update_status($tostatus);
2132
			}
2133
		} else {
2134
			if ($pkg_interface == "console") {
2135
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2136
					$tooutput = $static_output . $downloadProgress . "%";
2137
					if ($downloadProgress == 100) {
2138
						$tooutput = $tooutput . "\r";
2139
					}
2140
					update_output_window($tooutput);
2141
				}
2142
			} else {
2143
				$tooutput = $static_output . $downloadProgress . "%";
2144
				update_output_window($tooutput);
2145
			}
2146
		}
2147
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
2148
			update_progress_bar($downloadProgress, $first_progress_update);
2149
			$first_progress_update = FALSE;
2150
		}
2151
		$lastseen = $downloadProgress;
2152
	}
2153
	if ($fout) {
2154
		fwrite($fout, $string);
2155
	}
2156
	ob_flush();
2157
	return $length;
2158
}
2159

    
2160
/*
2161
 *   update_output_window: update bottom textarea dynamically.
2162
 */
2163
function update_output_window($text) {
2164
	global $pkg_interface;
2165
	$log = preg_replace("/\n/", "\\n", $text);
2166
	if ($pkg_interface != "console") {
2167
?>
2168
<script type="text/javascript">
2169
//<![CDATA[
2170
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
2171
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
2172
//]]>
2173
</script>
2174
<?php
2175
	}
2176
	/* ensure that contents are written out */
2177
	ob_flush();
2178
}
2179

    
2180
/*
2181
 *   update_status: update top textarea dynamically.
2182
 */
2183
function update_status($status) {
2184
	global $pkg_interface;
2185

    
2186
	if ($pkg_interface == "console") {
2187
		print ("{$status}");
2188
	}
2189

    
2190
	/* ensure that contents are written out */
2191
	ob_flush();
2192
}
2193

    
2194
/*
2195
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
2196
 */
2197
function update_progress_bar($percent, $first_time) {
2198
	global $pkg_interface;
2199
	if ($percent > 100) {
2200
		$percent = 1;
2201
	}
2202
	if ($pkg_interface <> "console") {
2203
		echo '<script type="text/javascript">';
2204
		echo "\n//<![CDATA[\n";
2205
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
2206
		echo "\n//]]>\n";
2207
		echo '</script>';
2208
	} else {
2209
		if (!($first_time)) {
2210
			echo "\x08\x08\x08\x08\x08";
2211
		}
2212
		echo sprintf("%4d%%", $percent);
2213
	}
2214
}
2215

    
2216
function update_alias_name($new_alias_name, $orig_alias_name) {
2217
	if (!$orig_alias_name) {
2218
		return;
2219
	}
2220

    
2221
	// Firewall rules
2222
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2223
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2224
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2225
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2226
	// NAT Rules
2227
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2228
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2229
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2230
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2231
	update_alias_names_upon_change(array('nat', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2232
	update_alias_names_upon_change(array('nat', 'rule'), array('local-port'), $new_alias_name, $orig_alias_name);
2233
	// NAT 1:1 Rules
2234
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('external'), $new_alias_name, $orig_alias_name);
2235
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2236
	update_alias_names_upon_change(array('nat', 'onetoone'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2237
	// NAT Outbound Rules
2238
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('source', 'network'), $new_alias_name, $orig_alias_name);
2239
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('sourceport'), $new_alias_name, $orig_alias_name);
2240
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2241
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('dstport'), $new_alias_name, $orig_alias_name);
2242
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2243
	// Alias in an alias
2244
	update_alias_names_upon_change(array('aliases', 'alias'), array('address'), $new_alias_name, $orig_alias_name);
2245
}
2246

    
2247
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2248
	global $g, $config, $pconfig, $debug;
2249
	if (!$origname) {
2250
		return;
2251
	}
2252

    
2253
	$sectionref = &$config;
2254
	foreach ($section as $sectionname) {
2255
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2256
			$sectionref = &$sectionref[$sectionname];
2257
		} else {
2258
			return;
2259
		}
2260
	}
2261

    
2262
	if ($debug) {
2263
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2264
		fwrite($fd, print_r($pconfig, true));
2265
	}
2266

    
2267
	if (is_array($sectionref)) {
2268
		foreach ($sectionref as $itemkey => $item) {
2269
			if ($debug) {
2270
				fwrite($fd, "$itemkey\n");
2271
			}
2272

    
2273
			$fieldfound = true;
2274
			$fieldref = &$sectionref[$itemkey];
2275
			foreach ($field as $fieldname) {
2276
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2277
					$fieldref = &$fieldref[$fieldname];
2278
				} else {
2279
					$fieldfound = false;
2280
					break;
2281
				}
2282
			}
2283
			if ($fieldfound && $fieldref == $origname) {
2284
				if ($debug) {
2285
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2286
				}
2287
				$fieldref = $new_alias_name;
2288
			}
2289
		}
2290
	}
2291

    
2292
	if ($debug) {
2293
		fclose($fd);
2294
	}
2295

    
2296
}
2297

    
2298
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2299
	/*
2300
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2301
	 * $type = if set to 'url' then subnets and ips will be returned,
2302
	 *         if set to 'url_ports' port-ranges and ports will be returned
2303
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2304
	 *
2305
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2306
	 */
2307

    
2308
	if (!file_exists($filename)) {
2309
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2310
		return null;
2311
	}
2312

    
2313
	if (filesize($filename) == 0) {
2314
		log_error(sprintf(gettext("Could not process empty file from alias: %s"), $filename));
2315
		return null;
2316
	}
2317
	$fd = @fopen($filename, 'r');
2318
	if (!$fd) {
2319
		log_error(sprintf(gettext("Could not process aliases from alias: %s"), $filename));
2320
		return null;
2321
	}
2322
	$items = array();
2323
	$comments = array();
2324
	/* NOTE: fgetss() is not a typo RTFM before being smart */
2325
	while (($fc = fgetss($fd)) !== FALSE) {
2326
		$tmp = trim($fc, " \t\n\r");
2327
		if (empty($tmp)) {
2328
			continue;
2329
		}
2330
		if (($kflc) && (strpos($tmp, '#') === 0)) {	// Keep Full Line Comments (lines beginning with #).
2331
			$comments[] = $tmp;
2332
		} else {
2333
			$tmp_str = strstr($tmp, '#', true);
2334
			if (!empty($tmp_str)) {
2335
				$tmp = $tmp_str;
2336
			}
2337
			$tmp_str = strstr($tmp, ' ', true);
2338
			if (!empty($tmp_str)) {
2339
				$tmp = $tmp_str;
2340
			}
2341
			$valid = (($type == "url" || $type == "urltable") && (is_ipaddr($tmp) || is_subnet($tmp))) ||
2342
				(($type == "url_ports" || $type == "urltable_ports") && is_port_or_range($tmp));
2343
			if ($valid) {
2344
				$items[] = $tmp;
2345
				if (count($items) == $max_items) {
2346
					break;
2347
				}
2348
			}
2349
		}
2350
	}
2351
	fclose($fd);
2352
	return array_merge($comments, $items);
2353
}
2354

    
2355
function update_alias_url_data() {
2356
	global $config, $g;
2357

    
2358
	$updated = false;
2359

    
2360
	/* item is a url type */
2361
	$lockkey = lock('aliasurl');
2362
	if (is_array($config['aliases']['alias'])) {
2363
		foreach ($config['aliases']['alias'] as $x => $alias) {
2364
			if (empty($alias['aliasurl'])) {
2365
				continue;
2366
			}
2367

    
2368
			$address = null;
2369
			foreach ($alias['aliasurl'] as $alias_url) {
2370
				/* fetch down and add in */
2371
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2372
				unlink($temp_filename);
2373
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2374
				mkdir($temp_filename);
2375
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2376
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2377
					continue;
2378
				}
2379

    
2380
				/* if the item is tar gzipped then extract */
2381
				if (stripos($alias_url, '.tgz')) {
2382
					if (!process_alias_tgz($temp_filename)) {
2383
						continue;
2384
					}
2385
				}
2386
				if (file_exists("{$temp_filename}/aliases")) {
2387
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2388
					mwexec("/bin/rm -rf {$temp_filename}");
2389
				}
2390
			}
2391
			if ($address != null) {
2392
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2393
				$updated = true;
2394
			}
2395
		}
2396
	}
2397
	unlock($lockkey);
2398

    
2399
	/* Report status to callers as well */
2400
	return $updated;
2401
}
2402

    
2403
function process_alias_tgz($temp_filename) {
2404
	if (!file_exists('/usr/bin/tar')) {
2405
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2406
		return false;
2407
	}
2408
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2409
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2410
	unlink("{$temp_filename}/aliases.tgz");
2411
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2412
	/* foreach through all extracted files and build up aliases file */
2413
	$fd = @fopen("{$temp_filename}/aliases", "w");
2414
	if (!$fd) {
2415
		log_error(sprintf(gettext("Could not open %s/aliases for writing!"), $temp_filename));
2416
		return false;
2417
	}
2418
	foreach ($files_to_process as $f2p) {
2419
		$tmpfd = @fopen($f2p, 'r');
2420
		if (!$tmpfd) {
2421
			log_error(sprintf(gettext('The following file could not be read %1$s from %2$s'), $f2p, $temp_filename));
2422
			continue;
2423
		}
2424
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2425
			fwrite($fd, $tmpbuf);
2426
		}
2427
		fclose($tmpfd);
2428
		unlink($f2p);
2429
	}
2430
	fclose($fd);
2431
	unset($tmpbuf);
2432

    
2433
	return true;
2434
}
2435

    
2436
function version_compare_dates($a, $b) {
2437
	$a_time = strtotime($a);
2438
	$b_time = strtotime($b);
2439

    
2440
	if ((!$a_time) || (!$b_time)) {
2441
		return FALSE;
2442
	} else {
2443
		if ($a_time < $b_time) {
2444
			return -1;
2445
		} elseif ($a_time == $b_time) {
2446
			return 0;
2447
		} else {
2448
			return 1;
2449
		}
2450
	}
2451
}
2452
function version_get_string_value($a) {
2453
	$strs = array(
2454
		0 => "ALPHA-ALPHA",
2455
		2 => "ALPHA",
2456
		3 => "BETA",
2457
		4 => "B",
2458
		5 => "C",
2459
		6 => "D",
2460
		7 => "RC",
2461
		8 => "RELEASE",
2462
		9 => "*"			// Matches all release levels
2463
	);
2464
	$major = 0;
2465
	$minor = 0;
2466
	foreach ($strs as $num => $str) {
2467
		if (substr($a, 0, strlen($str)) == $str) {
2468
			$major = $num;
2469
			$n = substr($a, strlen($str));
2470
			if (is_numeric($n)) {
2471
				$minor = $n;
2472
			}
2473
			break;
2474
		}
2475
	}
2476
	return "{$major}.{$minor}";
2477
}
2478
function version_compare_string($a, $b) {
2479
	// Only compare string parts if both versions give a specific release
2480
	// (If either version lacks a string part, assume intended to match all release levels)
2481
	if (isset($a) && isset($b)) {
2482
		return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
2483
	} else {
2484
		return 0;
2485
	}
2486
}
2487
function version_compare_numeric($a, $b) {
2488
	$a_arr = explode('.', rtrim($a, '.'));
2489
	$b_arr = explode('.', rtrim($b, '.'));
2490

    
2491
	foreach ($a_arr as $n => $val) {
2492
		if (array_key_exists($n, $b_arr)) {
2493
			// So far so good, both have values at this minor version level. Compare.
2494
			if ($val > $b_arr[$n]) {
2495
				return 1;
2496
			} elseif ($val < $b_arr[$n]) {
2497
				return -1;
2498
			}
2499
		} else {
2500
			// a is greater, since b doesn't have any minor version here.
2501
			return 1;
2502
		}
2503
	}
2504
	if (count($b_arr) > count($a_arr)) {
2505
		// b is longer than a, so it must be greater.
2506
		return -1;
2507
	} else {
2508
		// Both a and b are of equal length and value.
2509
		return 0;
2510
	}
2511
}
2512
function pfs_version_compare($cur_time, $cur_text, $remote) {
2513
	// First try date compare
2514
	$v = version_compare_dates($cur_time, $remote);
2515
	if ($v === FALSE) {
2516
		// If that fails, try to compare by string
2517
		// Before anything else, simply test if the strings are equal
2518
		if (($cur_text == $remote) || ($cur_time == $remote)) {
2519
			return 0;
2520
		}
2521
		list($cur_num, $cur_str) = explode('-', $cur_text);
2522
		list($rem_num, $rem_str) = explode('-', $remote);
2523

    
2524
		// First try to compare the numeric parts of the version string.
2525
		$v = version_compare_numeric($cur_num, $rem_num);
2526

    
2527
		// If the numeric parts are the same, compare the string parts.
2528
		if ($v == 0) {
2529
			return version_compare_string($cur_str, $rem_str);
2530
		}
2531
	}
2532
	return $v;
2533
}
2534
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2535
	global $g, $config;
2536

    
2537
	$urltable_prefix = "/var/db/aliastables/";
2538
	$urltable_filename = $urltable_prefix . $name . ".txt";
2539
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2540

    
2541
	// Make the aliases directory if it doesn't exist
2542
	if (!file_exists($urltable_prefix)) {
2543
		mkdir($urltable_prefix);
2544
	} elseif (!is_dir($urltable_prefix)) {
2545
		unlink($urltable_prefix);
2546
		mkdir($urltable_prefix);
2547
	}
2548

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

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

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

    
2563
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2564
			if ($type == "urltable_ports") {
2565
				$parsed_contents = group_ports($parsed_contents, true);
2566
			}
2567
			if (is_array($parsed_contents)) {
2568
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2569
			} else {
2570
				touch($urltable_filename);
2571
			}
2572

    
2573
			/* Remove existing archive and create an up to date archive if RAM disk is enabled. */
2574
			unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz");
2575
			if (isset($config['system']['use_mfs_tmpvar'])) {
2576
				mwexec("/usr/bin/tar -czf " . escapeshellarg("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz") . " -C / " . escapeshellarg($urltable_filename));
2577
			}
2578

    
2579
			unlink_if_exists($tmp_urltable_filename);
2580
		} else {
2581
			if (!$validateonly) {
2582
				touch($urltable_filename);
2583
			}
2584
			return false;
2585
		}
2586
		return true;
2587
	} else {
2588
		// File exists, and it doesn't need to be updated.
2589
		return -1;
2590
	}
2591
}
2592

    
2593
function get_include_contents($filename) {
2594
	if (is_file($filename)) {
2595
		ob_start();
2596
		include $filename;
2597
		$contents = ob_get_contents();
2598
		ob_end_clean();
2599
		return $contents;
2600
	}
2601
	return false;
2602
}
2603

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

    
2716
function get_country_name($country_code) {
2717
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2718
		return "";
2719
	}
2720

    
2721
	$country_names_xml = "/usr/local/share/pfSense/iso_3166-1_list_en.xml";
2722
	$country_names_contents = file_get_contents($country_names_xml);
2723
	$country_names = xml2array($country_names_contents);
2724

    
2725
	if ($country_code == "ALL") {
2726
		$country_list = array();
2727
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2728
			$country_list[] = array(
2729
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2730
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2731
		}
2732
		return $country_list;
2733
	}
2734

    
2735
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2736
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2737
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2738
		}
2739
	}
2740
	return "";
2741
}
2742

    
2743
/* sort by interface only, retain the original order of rules that apply to
2744
   the same interface */
2745
function filter_rules_sort() {
2746
	global $config;
2747

    
2748
	/* mark each rule with the sequence number (to retain the order while sorting) */
2749
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2750
		if (!is_array($config['filter']['rule'][$i])) {
2751
			$config['filter']['rule'][$i] = array();
2752
		}
2753
		$config['filter']['rule'][$i]['seq'] = $i;
2754
	}
2755

    
2756
	usort($config['filter']['rule'], "filter_rules_compare");
2757

    
2758
	/* strip the sequence numbers again */
2759
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2760
		unset($config['filter']['rule'][$i]['seq']);
2761
	}
2762
}
2763
function filter_rules_compare($a, $b) {
2764
	if (isset($a['floating']) && isset($b['floating'])) {
2765
		return $a['seq'] - $b['seq'];
2766
	} else if (isset($a['floating'])) {
2767
		return -1;
2768
	} else if (isset($b['floating'])) {
2769
		return 1;
2770
	} else if ($a['interface'] == $b['interface']) {
2771
		return $a['seq'] - $b['seq'];
2772
	} else {
2773
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2774
	}
2775
}
2776

    
2777
function generate_ipv6_from_mac($mac) {
2778
	$elements = explode(":", $mac);
2779
	if (count($elements) <> 6) {
2780
		return false;
2781
	}
2782

    
2783
	$i = 0;
2784
	$ipv6 = "fe80::";
2785
	foreach ($elements as $byte) {
2786
		if ($i == 0) {
2787
			$hexadecimal = substr($byte, 1, 2);
2788
			$bitmap = base_convert($hexadecimal, 16, 2);
2789
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2790
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2791
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2792
		}
2793
		$ipv6 .= $byte;
2794
		if ($i == 1) {
2795
			$ipv6 .= ":";
2796
		}
2797
		if ($i == 3) {
2798
			$ipv6 .= ":";
2799
		}
2800
		if ($i == 2) {
2801
			$ipv6 .= "ff:fe";
2802
		}
2803

    
2804
		$i++;
2805
	}
2806
	return $ipv6;
2807
}
2808

    
2809
/****f* pfsense-utils/load_mac_manufacturer_table
2810
 * NAME
2811
 *   load_mac_manufacturer_table
2812
 * INPUTS
2813
 *   none
2814
 * RESULT
2815
 *   returns associative array with MAC-Manufacturer pairs
2816
 ******/
2817
function load_mac_manufacturer_table() {
2818
	/* load MAC-Manufacture data from the file */
2819
	$macs = false;
2820
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2821
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2822
	}
2823
	if ($macs) {
2824
		foreach ($macs as $line) {
2825
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2826
				/* store values like this $mac_man['000C29']='VMware' */
2827
				$mac_man["$matches[1]"] = $matches[2];
2828
			}
2829
		}
2830
		return $mac_man;
2831
	} else {
2832
		return -1;
2833
	}
2834

    
2835
}
2836

    
2837
/****f* pfsense-utils/is_ipaddr_configured
2838
 * NAME
2839
 *   is_ipaddr_configured
2840
 * INPUTS
2841
 *   IP Address to check.
2842
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2843
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2844
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2845
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2846
 *     If check_subnets is true and cidrprefix is specified,
2847
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2848
 * RESULT
2849
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2850
*/
2851
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2852
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2853
		return true;
2854
	}
2855
	return false;
2856
}
2857

    
2858
/****f* pfsense-utils/where_is_ipaddr_configured
2859
 * NAME
2860
 *   where_is_ipaddr_configured
2861
 * INPUTS
2862
 *   IP Address to check.
2863
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2864
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2865
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2866
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2867
 *     If check_subnets is true and cidrprefix is specified,
2868
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2869
 * RESULT
2870
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2871
 *   If there are no matches then an empty array is returned.
2872
*/
2873
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2874
	global $config;
2875

    
2876
	$where_configured = array();
2877

    
2878
	$pos = strpos($ignore_if, '_virtualip');
2879
	if ($pos !== false) {
2880
		$ignore_vip_id = substr($ignore_if, $pos+10);
2881
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2882
	} else {
2883
		$ignore_vip_id = -1;
2884
		$ignore_vip_if = $ignore_if;
2885
	}
2886

    
2887
	$isipv6 = is_ipaddrv6($ipaddr);
2888

    
2889
	if ($isipv6) {
2890
		$ipaddr = text_to_compressed_ip6($ipaddr);
2891
	}
2892

    
2893
	if ($check_subnets) {
2894
		$cidrprefix = intval($cidrprefix);
2895
		if ($isipv6) {
2896
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2897
				$cidrprefix = 128;
2898
			}
2899
		} else {
2900
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2901
				$cidrprefix = 32;
2902
			}
2903
		}
2904
		$iflist = get_configured_interface_list();
2905
		foreach ($iflist as $if => $ifname) {
2906
			if ($ignore_if == $if) {
2907
				continue;
2908
			}
2909

    
2910
			if ($isipv6) {
2911
				$if_ipv6 = get_interface_ipv6($if);
2912
				$if_snbitsv6 = get_interface_subnetv6($if);
2913
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2914
					$where_entry = array();
2915
					$where_entry['if'] = $if;
2916
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2917
					$where_configured[] = $where_entry;
2918
				}
2919
			} else {
2920
				$if_ipv4 = get_interface_ip($if);
2921
				$if_snbitsv4 = get_interface_subnet($if);
2922
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
2923
					$where_entry = array();
2924
					$where_entry['if'] = $if;
2925
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
2926
					$where_configured[] = $where_entry;
2927
				}
2928
			}
2929
		}
2930
	} else {
2931
		if ($isipv6) {
2932
			$interface_list_ips = get_configured_ipv6_addresses();
2933
		} else {
2934
			$interface_list_ips = get_configured_ip_addresses();
2935
		}
2936

    
2937
		foreach ($interface_list_ips as $if => $ilips) {
2938
			if ($ignore_if == $if) {
2939
				continue;
2940
			}
2941
			if (strcasecmp($ipaddr, $ilips) == 0) {
2942
				$where_entry = array();
2943
				$where_entry['if'] = $if;
2944
				$where_entry['ip_or_subnet'] = $ilips;
2945
				$where_configured[] = $where_entry;
2946
			}
2947
		}
2948
	}
2949

    
2950
	if ($check_localip) {
2951
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, text_to_compressed_ip6($config['l2tp']['localip'])) == 0)) {
2952
			$where_entry = array();
2953
			$where_entry['if'] = 'l2tp';
2954
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
2955
			$where_configured[] = $where_entry;
2956
		}
2957
	}
2958

    
2959
	return $where_configured;
2960
}
2961

    
2962
/****f* pfsense-utils/pfSense_handle_custom_code
2963
 * NAME
2964
 *   pfSense_handle_custom_code
2965
 * INPUTS
2966
 *   directory name to process
2967
 * RESULT
2968
 *   globs the directory and includes the files
2969
 */
2970
function pfSense_handle_custom_code($src_dir) {
2971
	// Allow extending of the nat edit page and include custom input validation
2972
	if (is_dir("$src_dir")) {
2973
		$cf = glob($src_dir . "/*.inc");
2974
		foreach ($cf as $nf) {
2975
			if ($nf == "." || $nf == "..") {
2976
				continue;
2977
			}
2978
			// Include the extra handler
2979
			include_once("$nf");
2980
		}
2981
	}
2982
}
2983

    
2984
function set_language() {
2985
	global $config, $g;
2986

    
2987
	if (!empty($config['system']['language'])) {
2988
		$lang = $config['system']['language'];
2989
	} elseif (!empty($g['language'])) {
2990
		$lang = $g['language'];
2991
	}
2992
	$lang .= ".UTF-8";
2993

    
2994
	putenv("LANG={$lang}");
2995
	setlocale(LC_ALL, $lang);
2996
	textdomain("pfSense");
2997
	bindtextdomain("pfSense", "/usr/local/share/locale");
2998
	bind_textdomain_codeset("pfSense", $lang);
2999
}
3000

    
3001
function get_locale_list() {
3002
	$locales = array(
3003
		"bs" => gettext("Bosnian"),
3004
		"zh_CN" => gettext("Chinese"),
3005
		"zh_Hans_CN" => gettext("Chinese (Simplified, China)"),
3006
		"zh_HK" => gettext("Chinese (Hong Kong)"),
3007
		"zh_TW" => gettext("Chinese (Taiwan)"),
3008
		"nl" => gettext("Dutch"),
3009
		"en_US" => gettext("English"),
3010
		"fr" => gettext("French"),
3011
		"de_DE" => gettext("German (Germany)"),
3012
		"nb" => gettext("Norwegian Bokmål"),
3013
		"pl" => gettext("Polish"),
3014
		"pt_PT" => gettext("Portuguese"),
3015
		"pt_BR" => gettext("Portuguese (Brazil)"),
3016
		"ru" => gettext("Russian"),
3017
		"es" => gettext("Spanish"),
3018
		"es_AR" => gettext("Spanish (Argentina)"),
3019
	);
3020

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

    
3025
	//asort($locales);
3026

    
3027
	return $locales;
3028
}
3029

    
3030
function return_hex_ipv4($ipv4) {
3031
	if (!is_ipaddrv4($ipv4)) {
3032
		return(false);
3033
	}
3034

    
3035
	/* we need the hex form of the interface IPv4 address */
3036
	$ip4arr = explode(".", $ipv4);
3037
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
3038
}
3039

    
3040
function convert_ipv6_to_128bit($ipv6) {
3041
	if (!is_ipaddrv6($ipv6)) {
3042
		return(false);
3043
	}
3044

    
3045
	$ip6arr = array();
3046
	$ip6prefix = Net_IPv6::uncompress($ipv6);
3047
	$ip6arr = explode(":", $ip6prefix);
3048
	/* binary presentation of the prefix for all 128 bits. */
3049
	$ip6prefixbin = "";
3050
	foreach ($ip6arr as $element) {
3051
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3052
	}
3053
	return($ip6prefixbin);
3054
}
3055

    
3056
function convert_128bit_to_ipv6($ip6bin) {
3057
	if (strlen($ip6bin) <> 128) {
3058
		return(false);
3059
	}
3060

    
3061
	$ip6arr = array();
3062
	$ip6binarr = array();
3063
	$ip6binarr = str_split($ip6bin, 16);
3064
	foreach ($ip6binarr as $binpart) {
3065
		$ip6arr[] = dechex(bindec($binpart));
3066
	}
3067
	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
3068

    
3069
	return($ip6addr);
3070
}
3071

    
3072

    
3073
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3074
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3075
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3076
/* 6to4 is 16 bits, e.g. 65535 */
3077
function calculate_ipv6_delegation_length($if) {
3078
	global $config;
3079

    
3080
	if (!is_array($config['interfaces'][$if])) {
3081
		return false;
3082
	}
3083

    
3084
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3085
		case "6to4":
3086
			$pdlen = 16;
3087
			break;
3088
		case "6rd":
3089
			$rd6cfg = $config['interfaces'][$if];
3090
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3091
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
3092
			break;
3093
		case "dhcp6":
3094
			$dhcp6cfg = $config['interfaces'][$if];
3095
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3096
			break;
3097
		default:
3098
			$pdlen = 0;
3099
			break;
3100
	}
3101
	return($pdlen);
3102
}
3103

    
3104
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3105
	$prefix = Net_IPv6::uncompress($prefix, true);
3106
	$suffix = Net_IPv6::uncompress($suffix, true);
3107

    
3108
	/*
3109
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3110
	 *                ^^^^ ^
3111
	 *                |||| \-> 64
3112
	 *                |||\---> 63, 62, 61, 60
3113
	 *                ||\----> 56
3114
	 *                |\-----> 52
3115
	 *                \------> 48
3116
	 */
3117

    
3118
	switch ($len) {
3119
	case 48:
3120
		$prefix_len = 15;
3121
		break;
3122
	case 52:
3123
		$prefix_len = 16;
3124
		break;
3125
	case 56:
3126
		$prefix_len = 17;
3127
		break;
3128
	case 59:
3129
	case 60:
3130
		$prefix_len = 18;
3131
		break;
3132
	/*
3133
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
3134
	 * we let user chose this bit it can end up out of PD network
3135
	 *
3136
	 * Leave this with 20 for now until we find a way to let user
3137
	 * chose it. The side-effect is users with PD with one of these
3138
	 * lengths will not be able to setup DHCP server range for full
3139
	 * PD size, only for last /64 network
3140
	 */
3141
	case 63:
3142
	case 62:
3143
	case 61:
3144
	default:
3145
		$prefix_len = 20;
3146
		break;
3147
	}
3148

    
3149
	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
3150
	    substr($suffix, $prefix_len));
3151
}
3152

    
3153
function dhcpv6_pd_str_help($pdlen) {
3154
	$result = '';
3155

    
3156
	switch ($pdlen) {
3157
	case 48:
3158
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
3159
		break;
3160
	case 52:
3161
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
3162
		break;
3163
	case 56:
3164
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
3165
		break;
3166
	case 59:
3167
	case 60:
3168
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
3169
		break;
3170
	/*
3171
	 * XXX 63, 62 and 61 should use same mask as 60 but if
3172
	 * we let the user choose this bit it can end up out of PD network
3173
	 *
3174
	 * Leave this with the same as 64 for now until we find a way to
3175
	 * let the user choose it. The side-effect is users with PD with one
3176
	 * of these lengths will not be able to setup DHCP server ranges
3177
	 * for full PD size, only for last /64 network
3178
	 */
3179
	case 61:
3180
	case 62:
3181
	case 63:
3182
	case 64:
3183
	default:
3184
		$result = '::xxxx:xxxx:xxxx:xxxx';
3185
		break;
3186
	}
3187

    
3188
	return $result;
3189
}
3190

    
3191
function huawei_rssi_to_string($rssi) {
3192
	$dbm = array();
3193
	$i = 0;
3194
	$dbstart = -113;
3195
	while ($i < 32) {
3196
		$dbm[$i] = $dbstart + ($i * 2);
3197
		$i++;
3198
	}
3199
	$percent = round(($rssi / 31) * 100);
3200
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3201
	return $string;
3202
}
3203

    
3204
function huawei_mode_to_string($mode, $submode) {
3205
	$modes[0] = gettext("None");
3206
	$modes[1] = "AMPS";
3207
	$modes[2] = "CDMA";
3208
	$modes[3] = "GSM/GPRS";
3209
	$modes[4] = "HDR";
3210
	$modes[5] = "WCDMA";
3211
	$modes[6] = "GPS";
3212

    
3213
	$submodes[0] = gettext("No Service");
3214
	$submodes[1] = "GSM";
3215
	$submodes[2] = "GPRS";
3216
	$submodes[3] = "EDGE";
3217
	$submodes[4] = "WCDMA";
3218
	$submodes[5] = "HSDPA";
3219
	$submodes[6] = "HSUPA";
3220
	$submodes[7] = "HSDPA+HSUPA";
3221
	$submodes[8] = "TD-SCDMA";
3222
	$submodes[9] = "HSPA+";
3223
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3224
	return $string;
3225
}
3226

    
3227
function huawei_service_to_string($state) {
3228
	$modes[0] = gettext("No Service");
3229
	$modes[1] = gettext("Restricted Service");
3230
	$modes[2] = gettext("Valid Service");
3231
	$modes[3] = gettext("Restricted Regional Service");
3232
	$modes[4] = gettext("Powersaving Service");
3233
	$modes[255] = gettext("Unknown Service");
3234
	$string = $modes[$state];
3235
	return $string;
3236
}
3237

    
3238
function huawei_simstate_to_string($state) {
3239
	$modes[0] = gettext("Invalid SIM/locked State");
3240
	$modes[1] = gettext("Valid SIM State");
3241
	$modes[2] = gettext("Invalid SIM CS State");
3242
	$modes[3] = gettext("Invalid SIM PS State");
3243
	$modes[4] = gettext("Invalid SIM CS/PS State");
3244
	$modes[255] = gettext("Missing SIM State");
3245
	$string = $modes[$state];
3246
	return $string;
3247
}
3248

    
3249
function zte_rssi_to_string($rssi) {
3250
	return huawei_rssi_to_string($rssi);
3251
}
3252

    
3253
function zte_mode_to_string($mode, $submode) {
3254
	$modes[0] = gettext("No Service");
3255
	$modes[1] = gettext("Limited Service");
3256
	$modes[2] = "GPRS";
3257
	$modes[3] = "GSM";
3258
	$modes[4] = "UMTS";
3259
	$modes[5] = "EDGE";
3260
	$modes[6] = "HSDPA";
3261

    
3262
	$submodes[0] = "CS_ONLY";
3263
	$submodes[1] = "PS_ONLY";
3264
	$submodes[2] = "CS_PS";
3265
	$submodes[3] = "CAMPED";
3266
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3267
	return $string;
3268
}
3269

    
3270
function zte_service_to_string($service) {
3271
	$modes[0] = gettext("Initializing Service");
3272
	$modes[1] = gettext("Network Lock error Service");
3273
	$modes[2] = gettext("Network Locked Service");
3274
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3275
	$string = $modes[$service];
3276
	return $string;
3277
}
3278

    
3279
function zte_simstate_to_string($state) {
3280
	$modes[0] = gettext("No action State");
3281
	$modes[1] = gettext("Network lock State");
3282
	$modes[2] = gettext("(U)SIM card lock State");
3283
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3284
	$string = $modes[$state];
3285
	return $string;
3286
}
3287

    
3288
function get_configured_pppoe_server_interfaces() {
3289
	global $config;
3290
	$iflist = array();
3291
	if (is_array($config['pppoes']['pppoe'])) {
3292
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3293
			if ($pppoe['mode'] == "server") {
3294
				$int = "poes". $pppoe['pppoeid'];
3295
				$iflist[$int] = strtoupper($int);
3296
			}
3297
		}
3298
	}
3299
	return $iflist;
3300
}
3301

    
3302
function get_pppoes_child_interfaces($ifpattern) {
3303
	$if_arr = array();
3304
	if ($ifpattern == "") {
3305
		return;
3306
	}
3307

    
3308
	exec("/sbin/ifconfig", $out, $ret);
3309
	foreach ($out as $line) {
3310
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3311
			$if_arr[] = $match[1];
3312
		}
3313
	}
3314
	return $if_arr;
3315

    
3316
}
3317

    
3318
/****f* pfsense-utils/pkg_call_plugins
3319
 * NAME
3320
 *   pkg_call_plugins
3321
 * INPUTS
3322
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3323
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3324
 * RESULT
3325
 *   returns associative array results from the plugin calls for each package
3326
 * NOTES
3327
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3328
 ******/
3329
function pkg_call_plugins($plugin_type, $plugin_params) {
3330
	global $g, $config;
3331
	$results = array();
3332
	if (!is_array($config['installedpackages']['package'])) {
3333
		return $results;
3334
	}
3335
	foreach ($config['installedpackages']['package'] as $package) {
3336
		if (is_array($package['plugins']['item'])) {
3337
			foreach ($package['plugins']['item'] as $plugin) {
3338
				if ($plugin['type'] == $plugin_type) {
3339
					if (file_exists($package['include_file'])) {
3340
						require_once($package['include_file']);
3341
					} else {
3342
						continue;
3343
					}
3344
					$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3345
					$plugin_function = $pkgname . '_'. $plugin_type;
3346
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3347
				}
3348
			}
3349
		}
3350
	}
3351
	return $results;
3352
}
3353

    
3354
// Convert IPv6 addresses to lower case
3355
function addrtolower($ip) {
3356
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3357
		return(strtolower($ip));
3358
	} else {
3359
		return($ip);
3360
	}
3361
}
3362

    
3363
function compare_by_name($a, $b) {
3364
	return strcasecmp($a['name'], $b['name']);
3365
}
3366
?>
(38-38/60)