Project

General

Profile

Download (91.3 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * pfsense-utils.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 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
			if (strpos($css, "login") == 0) {	// Don't display any login page related CSS files
184
				if (strpos($css, "BETA") != 0) {
185
					array_push($betacss, $css);
186
				} else if (strpos($css, "pfSense") != 0) {
187
					array_push($pfscss, $css);
188
				} else {
189
					array_push($usrcss, $css);
190
				}
191
			}
192
		}
193

    
194
		$css = array_merge($pfscss, $betacss, $usrcss);
195

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

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

    
215
	$csslist = get_css_files();
216

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

    
221
	$section->addInput(new Form_Select(
222
		'webguicss',
223
		'Theme',
224
		$value,
225
		$csslist
226
	))->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>');
227
}
228

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

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

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

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

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

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

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

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

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

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

    
321
	$group = new Form_Group('Associated Panels Show/Hide');
322

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

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

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

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

    
351
	$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.');
352

    
353
	$section->add($group);
354
}
355

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

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

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

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

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

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

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

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

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

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

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

    
479
		if ($has_created_time) {
480
			$section->addInput(new Form_StaticText(
481
				'Created',
482
				sprintf(
483
					gettext('%1$s by %2$s'),
484
					date(gettext("n/j/y H:i:s"), $created['time']),
485
					$created['username'])
486
			));
487
		}
488

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

    
499
		$form->add($section);
500
	}
501
}
502

    
503
function hardware_offloading_applyflags($iface) {
504
	global $config;
505

    
506
	$flags_on = 0;
507
	$flags_off = 0;
508
	$options = pfSense_get_interface_addresses($iface);
509

    
510
	if (isset($config['system']['disablechecksumoffloading'])) {
511
		if (isset($options['encaps']['txcsum'])) {
512
			$flags_off |= IFCAP_TXCSUM;
513
		}
514
		if (isset($options['encaps']['rxcsum'])) {
515
			$flags_off |= IFCAP_RXCSUM;
516
		}
517
		if (isset($options['encaps']['txcsum6'])) {
518
			$flags_off |= IFCAP_TXCSUM_IPV6;
519
		}
520
		if (isset($options['encaps']['rxcsum6'])) {
521
			$flags_off |= IFCAP_RXCSUM_IPV6;
522
		}
523
	} else {
524
		if (isset($options['caps']['txcsum'])) {
525
			$flags_on |= IFCAP_TXCSUM;
526
		}
527
		if (isset($options['caps']['rxcsum'])) {
528
			$flags_on |= IFCAP_RXCSUM;
529
		}
530
		if (isset($options['caps']['txcsum6'])) {
531
			$flags_on |= IFCAP_TXCSUM_IPV6;
532
		}
533
		if (isset($options['caps']['rxcsum6'])) {
534
			$flags_on |= IFCAP_RXCSUM_IPV6;
535
		}
536
	}
537

    
538
	if (isset($config['system']['disablesegmentationoffloading'])) {
539
		$flags_off |= IFCAP_TSO;
540
	} else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6'])) {
541
		$flags_on |= IFCAP_TSO;
542
	}
543

    
544
	if (isset($config['system']['disablelargereceiveoffloading'])) {
545
		$flags_off |= IFCAP_LRO;
546
	} else if (isset($options['caps']['lro'])) {
547
		$flags_on |= IFCAP_LRO;
548
	}
549

    
550
	pfSense_interface_capabilities($iface, -$flags_off);
551
	pfSense_interface_capabilities($iface, $flags_on);
552
}
553

    
554
/****f* pfsense-utils/enable_hardware_offloading
555
 * NAME
556
 *   enable_hardware_offloading - Enable a NIC's supported hardware features.
557
 * INPUTS
558
 *   $interface	- string containing the physical interface to work on.
559
 * RESULT
560
 *   null
561
 * NOTES
562
 *   This function only supports the fxp driver's loadable microcode.
563
 ******/
564
function enable_hardware_offloading($interface) {
565
	global $g, $config;
566

    
567
	$int = get_real_interface($interface);
568
	if (empty($int)) {
569
		return;
570
	}
571

    
572
	if (!isset($config['system']['do_not_use_nic_microcode'])) {
573
		/* translate wan, lan, opt -> real interface if needed */
574
		$int_family = preg_split("/[0-9]+/", $int);
575
		$supported_ints = array('fxp');
576
		if (in_array($int_family, $supported_ints)) {
577
			if (does_interface_exist($int)) {
578
				pfSense_interface_flags($int, IFF_LINK0);
579
			}
580
		}
581
	}
582

    
583
	/* This is mostly for vlans and ppp types */
584
	$realhwif = get_parent_interface($interface);
585
	if ($realhwif[0] == $int) {
586
		hardware_offloading_applyflags($int);
587
	} else {
588
		hardware_offloading_applyflags($realhwif[0]);
589
		hardware_offloading_applyflags($int);
590
	}
591
}
592

    
593
/****f* pfsense-utils/is_alias_inuse
594
 * NAME
595
 *   checks to see if an alias is currently in use by a rule
596
 * INPUTS
597
 *
598
 * RESULT
599
 *   true or false
600
 * NOTES
601
 *
602
 ******/
603
function is_alias_inuse($alias) {
604
	global $g, $config;
605

    
606
	if ($alias == "") {
607
		return false;
608
	}
609
	/* loop through firewall rules looking for alias in use */
610
	if (is_array($config['filter']['rule'])) {
611
		foreach ($config['filter']['rule'] as $rule) {
612
			if ($rule['source']['address']) {
613
				if ($rule['source']['address'] == $alias) {
614
					return true;
615
				}
616
			}
617
			if ($rule['destination']['address']) {
618
				if ($rule['destination']['address'] == $alias) {
619
					return true;
620
				}
621
			}
622
		}
623
	}
624
	/* loop through nat rules looking for alias in use */
625
	if (is_array($config['nat']['rule'])) {
626
		foreach ($config['nat']['rule'] as $rule) {
627
			if ($rule['target'] && $rule['target'] == $alias) {
628
				return true;
629
			}
630
			if ($rule['source']['address'] && $rule['source']['address'] == $alias) {
631
				return true;
632
			}
633
			if ($rule['destination']['address'] && $rule['destination']['address'] == $alias) {
634
				return true;
635
			}
636
		}
637
	}
638
	return false;
639
}
640

    
641
/****f* pfsense-utils/is_schedule_inuse
642
 * NAME
643
 *   checks to see if a schedule is currently in use by a rule
644
 * INPUTS
645
 *
646
 * RESULT
647
 *   true or false
648
 * NOTES
649
 *
650
 ******/
651
function is_schedule_inuse($schedule) {
652
	global $g, $config;
653

    
654
	if ($schedule == "") {
655
		return false;
656
	}
657
	/* loop through firewall rules looking for schedule in use */
658
	if (is_array($config['filter']['rule'])) {
659
		foreach ($config['filter']['rule'] as $rule) {
660
			if ($rule['sched'] == $schedule) {
661
				return true;
662
			}
663
		}
664
	}
665
	return false;
666
}
667

    
668
/****f* pfsense-utils/setup_microcode
669
 * NAME
670
 *   enumerates all interfaces and calls enable_hardware_offloading which
671
 *   enables a NIC's supported hardware features.
672
 * INPUTS
673
 *
674
 * RESULT
675
 *   null
676
 * NOTES
677
 *   This function only supports the fxp driver's loadable microcode.
678
 ******/
679
function setup_microcode() {
680

    
681
	/* if list */
682
	$iflist = get_configured_interface_list(true);
683
	foreach ($iflist as $if => $ifdescr) {
684
		enable_hardware_offloading($if);
685
	}
686
	unset($iflist);
687
}
688

    
689
/****f* pfsense-utils/get_carp_status
690
 * NAME
691
 *   get_carp_status - Return whether CARP is enabled or disabled.
692
 * RESULT
693
 *   boolean	- true if CARP is enabled, false if otherwise.
694
 ******/
695
function get_carp_status() {
696
	/* grab the current status of carp */
697
	$status = get_single_sysctl('net.inet.carp.allow');
698
	return (intval($status) > 0);
699
}
700

    
701
/*
702
 * convert_ip_to_network_format($ip, $subnet): converts an ip address to network form
703

    
704
 */
705
function convert_ip_to_network_format($ip, $subnet) {
706
	$ipsplit = explode('.', $ip);
707
	$string = $ipsplit[0] . "." . $ipsplit[1] . "." . $ipsplit[2] . ".0/" . $subnet;
708
	return $string;
709
}
710

    
711
/*
712
 * get_carp_interface_status($carpid): returns the status of a carp uniqid
713
 */
714
function get_carp_interface_status($carpid) {
715

    
716
	$carpiface = get_configured_vip_interface($carpid);
717
	if ($carpiface == NULL)
718
		return "";
719
	$interface = get_real_interface($carpiface);
720
	if ($interface == NULL)
721
		return "";
722
	$vip = get_configured_vip($carpid);
723
	if ($vip == NULL || !isset($vip['vhid']))
724
		return "";
725

    
726
	$vhid = $vip['vhid'];
727
	$carp_query = '';
728
	$_gb = exec("/sbin/ifconfig {$interface} | /usr/bin/grep \"carp:.* vhid {$vhid} \"", $carp_query);
729
	foreach ($carp_query as $int) {
730
		if (stripos($int, "MASTER"))
731
			return "MASTER";
732
		elseif (stripos($int, "BACKUP"))
733
			return "BACKUP";
734
		elseif (stripos($int, "INIT"))
735
			return "INIT";
736
	}
737

    
738
	return "";
739
}
740

    
741
/*
742
 * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
743
 */
744
function get_pfsync_interface_status($pfsyncinterface) {
745
	if (!does_interface_exist($pfsyncinterface)) {
746
		return;
747
	}
748

    
749
	return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
750
}
751

    
752
/*
753
 * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
754
 */
755
function add_rule_to_anchor($anchor, $rule, $label) {
756
	mwexec("echo " . escapeshellarg($rule) . " | /sbin/pfctl -a " . escapeshellarg($anchor) . ":" . escapeshellarg($label) . " -f -");
757
}
758

    
759
/*
760
 * remove_text_from_file
761
 * remove $text from file $file
762
 */
763
function remove_text_from_file($file, $text) {
764
	if (!file_exists($file) && !is_writable($file)) {
765
		return;
766
	}
767
	$filecontents = file_get_contents($file);
768
	$text = str_replace($text, "", $filecontents);
769
	@file_put_contents($file, $text);
770
}
771

    
772
/*
773
 *   after_sync_bump_adv_skew(): create skew values by 1S
774
 */
775
function after_sync_bump_adv_skew() {
776
	global $config, $g;
777
	$processed_skew = 1;
778
	$a_vip = &$config['virtualip']['vip'];
779
	foreach ($a_vip as $vipent) {
780
		if ($vipent['advskew'] <> "") {
781
			$processed_skew = 1;
782
			$vipent['advskew'] = $vipent['advskew']+1;
783
		}
784
	}
785
	if ($processed_skew == 1) {
786
		write_config(gettext("After synch increase advertising skew"));
787
	}
788
}
789

    
790
/*
791
 * get_filename_from_url($url): converts a url to its filename.
792
 */
793
function get_filename_from_url($url) {
794
	return basename($url);
795
}
796

    
797
/*
798
 *   get_dir: return an array of $dir
799
 */
800
function get_dir($dir) {
801
	$dir_array = array();
802
	$d = dir($dir);
803
	if (!is_object($d)) {
804
		return array();
805
	}
806
	while (false !== ($entry = $d->read())) {
807
		array_push($dir_array, $entry);
808
	}
809
	$d->close();
810
	return $dir_array;
811
}
812

    
813
/****f* pfsense-utils/WakeOnLan
814
 * NAME
815
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
816
 * RESULT
817
 *   true/false - true if the operation was successful
818
 ******/
819
function WakeOnLan($addr, $mac) {
820
	$addr_byte = explode(':', $mac);
821
	$hw_addr = '';
822

    
823
	for ($a = 0; $a < 6; $a++) {
824
		$hw_addr .= chr(hexdec($addr_byte[$a]));
825
	}
826

    
827
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
828

    
829
	for ($a = 1; $a <= 16; $a++) {
830
		$msg .= $hw_addr;
831
	}
832

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

    
850
	return false;
851
}
852

    
853
/*
854
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
855
 *					 Useful for finding paths and stripping file extensions.
856
 */
857
function reverse_strrchr($haystack, $needle) {
858
	if (!is_string($haystack)) {
859
		return;
860
	}
861
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
862
}
863

    
864
/*
865
 *  backup_config_section($section): returns as an xml file string of
866
 *                                   the configuration section
867
 */
868
function backup_config_section($section_name) {
869
	global $config;
870
	$new_section = &$config[$section_name];
871
	/* generate configuration XML */
872
	$xmlconfig = dump_xml_config($new_section, $section_name);
873
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
874
	return $xmlconfig;
875
}
876

    
877
/*
878
 *  restore_config_section($section_name, new_contents): restore a configuration section,
879
 *                                                  and write the configuration out
880
 *                                                  to disk/cf.
881
 */
882
function restore_config_section($section_name, $new_contents) {
883
	global $config, $g;
884
	$fout = fopen("{$g['tmp_path']}/tmpxml", "w");
885
	fwrite($fout, $new_contents);
886
	fclose($fout);
887

    
888
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
889
	if ($xml['pfsense']) {
890
		$xml = $xml['pfsense'];
891
	}
892
	else if ($xml['m0n0wall']) {
893
		$xml = $xml['m0n0wall'];
894
	}
895
	if ($xml[$section_name]) {
896
		$section_xml = $xml[$section_name];
897
	} else {
898
		$section_xml = -1;
899
	}
900

    
901
	@unlink($g['tmp_path'] . "/tmpxml");
902
	if ($section_xml === -1) {
903
		return false;
904
	}
905
	$config[$section_name] = &$section_xml;
906
	if (file_exists("{$g['tmp_path']}/config.cache")) {
907
		unlink("{$g['tmp_path']}/config.cache");
908
	}
909
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
910
	disable_security_checks();
911
	return true;
912
}
913

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

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

    
965
/*
966
 * host_firmware_version(): Return the versions used in this install
967
 */
968
function host_firmware_version($tocheck = "") {
969
	global $g, $config;
970

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

    
973
	return array(
974
		"firmware" => array("version" => $g['product_version']),
975
		"kernel"   => array("version" => $os_version),
976
		"base"     => array("version" => $os_version),
977
		"platform" => $g['platform'],
978
		"config_version" => $config['version']
979
	);
980
}
981

    
982
function get_disk_info() {
983
	$diskout = "";
984
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
985
	return explode(' ', $diskout[0]);
986
}
987

    
988
/****f* pfsense-utils/strncpy
989
 * NAME
990
 *   strncpy - copy strings
991
 * INPUTS
992
 *   &$dst, $src, $length
993
 * RESULT
994
 *   none
995
 ******/
996
function strncpy(&$dst, $src, $length) {
997
	if (strlen($src) > $length) {
998
		$dst = substr($src, 0, $length);
999
	} else {
1000
		$dst = $src;
1001
	}
1002
}
1003

    
1004
/****f* pfsense-utils/reload_interfaces_sync
1005
 * NAME
1006
 *   reload_interfaces - reload all interfaces
1007
 * INPUTS
1008
 *   none
1009
 * RESULT
1010
 *   none
1011
 ******/
1012
function reload_interfaces_sync() {
1013
	global $config, $g;
1014

    
1015
	if ($g['debug']) {
1016
		log_error(gettext("reload_interfaces_sync() is starting."));
1017
	}
1018

    
1019
	/* parse config.xml again */
1020
	$config = parse_config(true);
1021

    
1022
	/* enable routing */
1023
	system_routing_enable();
1024
	if ($g['debug']) {
1025
		log_error(gettext("Enabling system routing"));
1026
	}
1027

    
1028
	if ($g['debug']) {
1029
		log_error(gettext("Cleaning up Interfaces"));
1030
	}
1031

    
1032
	/* set up interfaces */
1033
	interfaces_configure();
1034
}
1035

    
1036
/****f* pfsense-utils/reload_all
1037
 * NAME
1038
 *   reload_all - triggers a reload of all settings
1039
 *   * INPUTS
1040
 *   none
1041
 * RESULT
1042
 *   none
1043
 ******/
1044
function reload_all() {
1045
	send_event("service reload all");
1046
}
1047

    
1048
/****f* pfsense-utils/reload_interfaces
1049
 * NAME
1050
 *   reload_interfaces - triggers a reload of all interfaces
1051
 * INPUTS
1052
 *   none
1053
 * RESULT
1054
 *   none
1055
 ******/
1056
function reload_interfaces() {
1057
	send_event("interface all reload");
1058
}
1059

    
1060
/****f* pfsense-utils/reload_all_sync
1061
 * NAME
1062
 *   reload_all - reload all settings
1063
 *   * INPUTS
1064
 *   none
1065
 * RESULT
1066
 *   none
1067
 ******/
1068
function reload_all_sync() {
1069
	global $config, $g;
1070

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

    
1074
	/* set up our timezone */
1075
	system_timezone_configure();
1076

    
1077
	/* set up our hostname */
1078
	system_hostname_configure();
1079

    
1080
	/* make hosts file */
1081
	system_hosts_generate();
1082

    
1083
	/* generate resolv.conf */
1084
	system_resolvconf_generate();
1085

    
1086
	/* enable routing */
1087
	system_routing_enable();
1088

    
1089
	/* set up interfaces */
1090
	interfaces_configure();
1091

    
1092
	/* start dyndns service */
1093
	services_dyndns_configure();
1094

    
1095
	/* configure cron service */
1096
	configure_cron();
1097

    
1098
	/* start the NTP client */
1099
	system_ntp_configure();
1100

    
1101
	/* sync pw database */
1102
	unlink_if_exists("/etc/spwd.db.tmp");
1103
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
1104

    
1105
	/* restart sshd */
1106
	send_event("service restart sshd");
1107

    
1108
	/* restart webConfigurator if needed */
1109
	send_event("service restart webgui");
1110
}
1111

    
1112
function setup_serial_port($when = "save", $path = "") {
1113
	global $g, $config;
1114
	$ttys_file = "{$path}/etc/ttys";
1115
	$boot_config_file = "{$path}/boot.config";
1116
	$loader_conf_file = "{$path}/boot/loader.conf";
1117
	/* serial console - write out /boot.config */
1118
	if (file_exists($boot_config_file)) {
1119
		$boot_config = file_get_contents($boot_config_file);
1120
	} else {
1121
		$boot_config = "";
1122
	}
1123

    
1124
	$serialspeed = (is_numeric($config['system']['serialspeed'])) ? $config['system']['serialspeed'] : "115200";
1125
	$serial_only = false;
1126
	$vga_only = false;
1127

    
1128
	$specific_platform = system_identify_specific_platform();
1129
	if ($specific_platform['name'] == 'XG-1540' ||
1130
	    $specific_platform['name'] == 'Turbot Dual-E') {
1131
		$vga_only = true;
1132
	} elseif ($specific_platform['name'] == 'RCC-VE' ||
1133
	    $specific_platform['name'] == 'RCC' ||
1134
	    $specific_platform['name'] == 'RCC-DFF' ||
1135
	    $specific_platform['name'] == 'apu2') {
1136
		$serial_only = true;
1137
	}
1138

    
1139
	$boot_config_split = explode("\n", $boot_config);
1140
	$data = array();
1141
	foreach ($boot_config_split as $bcs) {
1142
		/* Ignore -D and -h lines now */
1143
		if (!empty($bcs) && !stristr($bcs, "-D") &&
1144
		    !stristr($bcs, "-h")) {
1145
			$data[] = $bcs;
1146
		}
1147
	}
1148
	if ($serial_only === true) {
1149
		$data[] = "-S{$serialspeed} -h";
1150
	} elseif (is_serial_enabled()) {
1151
		$data[] = "-S{$serialspeed} -D";
1152
	}
1153

    
1154
	if (empty($data)) {
1155
		@unlink($boot_conf_file);
1156
	} else {
1157
		safe_write_file($boot_config_file, $data);
1158
	}
1159

    
1160
	unset($boot_config, $boot_config_file, $boot_config_split);
1161

    
1162
	/* serial console - write out /boot/loader.conf */
1163
	if ($when == "upgrade") {
1164
		system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1165
	}
1166

    
1167
	$loader_conf = file_get_contents($loader_conf_file);
1168
	$loader_conf_split = explode("\n", $loader_conf);
1169

    
1170
	$data = array();
1171
	// Loop through and only add lines that are not empty, and which
1172
	//  do not contain a console directive.
1173
	foreach ($loader_conf_split as $bcs) {
1174
		if (!empty($bcs) &&
1175
		    (stripos($bcs, "console") === false) &&
1176
		    (stripos($bcs, "boot_multicons") === false) &&
1177
		    (stripos($bcs, "boot_serial") === false) &&
1178
		    (stripos($bcs, "hw.usb.no_pf") === false) &&
1179
		    (stripos($bcs, "hint.uart.0.flags") === false) &&
1180
		    (stripos($bcs, "hint.uart.1.flags") === false)) {
1181
			$data[] = $bcs;
1182
		}
1183
	}
1184

    
1185
	if ($serial_only === true) {
1186
		$data[] = 'boot_serial="YES"';
1187
		$data[] = 'console="comconsole"';
1188
	} elseif ($vga_only === true) {
1189
		$data[] = 'console="vidconsole"';
1190
	} elseif (is_serial_enabled()) {
1191
		$data[] = 'boot_multicons="YES"';
1192
		$data[] = 'boot_serial="YES"';
1193
		$primaryconsole = isset($g['primaryconsole_force']) ?
1194
		    $g['primaryconsole_force'] :
1195
		    $config['system']['primaryconsole'];
1196
		switch ($primaryconsole) {
1197
			case "video":
1198
				$data[] = 'console="vidconsole,comconsole"';
1199
				break;
1200
			case "serial":
1201
			default:
1202
				$data[] = 'console="comconsole,vidconsole"';
1203
		}
1204
	}
1205
	$data[] = 'comconsole_speed="' . $serialspeed . '"';
1206

    
1207
	if ($specific_platform['name'] == 'RCC-VE' ||
1208
	    $specific_platform['name'] == 'RCC' ||
1209
	    $specific_platform['name'] == 'RCC-DFF') {
1210
		$data[] = 'comconsole_port="0x2F8"';
1211
		$data[] = 'hint.uart.0.flags="0x00"';
1212
		$data[] = 'hint.uart.1.flags="0x10"';
1213
	}
1214
	$data[] = 'hw.usb.no_pf="1"';
1215

    
1216
	safe_write_file($loader_conf_file, $data);
1217

    
1218
	unset($loader_conf, $loader_conf_split, $loader_config_file);
1219

    
1220
	$ttys = file_get_contents($ttys_file);
1221
	$ttys_split = explode("\n", $ttys);
1222

    
1223
	$data = array();
1224

    
1225
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1226

    
1227
	if (isset($config['system']['disableconsolemenu'])) {
1228
		$console_type = 'Pc';
1229
		$serial_type = '3wire';
1230
	} else {
1231
		$console_type = 'al.Pc';
1232
		$serial_type = 'al.3wire';
1233
	}
1234

    
1235
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1236
	$ttyv0_line =
1237
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\txterm\ton\tsecure";
1238
	$ttyu_line =
1239
	    "\"/usr/libexec/getty {$serial_type}\"\tvt100\t{$on_off}\tsecure";
1240

    
1241
	$found = array();
1242

    
1243
	foreach ($ttys_split as $tty) {
1244
		/* Ignore blank lines */
1245
		if (empty($tty)) {
1246
			continue;
1247
		}
1248

    
1249
		if (stristr($tty, "ttyv0")) {
1250
			$found['ttyv0'] = 1;
1251
			$data[] = $ttyv0_line;
1252
		} elseif (stristr($tty, "ttyu")) {
1253
			$ttyn = substr($tty, 0, 5);
1254
			$found[$ttyn] = 1;
1255
			$data[] = "{$ttyn}\t{$ttyu_line}";
1256
		} elseif (substr($tty, 0, 7) == 'console') {
1257
			$found['console'] = 1;
1258
			$data[] = $tty;
1259
		} else {
1260
			$data[] = $tty;
1261
		}
1262
	}
1263
	unset($on_off, $console_type, $serial_type);
1264

    
1265
	/* Detect missing main lines on original file and try to rebuild it */
1266
	$items = array(
1267
		'console',
1268
		'ttyv0',
1269
		'ttyu0',
1270
		'ttyu1',
1271
		'ttyu2',
1272
		'ttyu3'
1273
	);
1274

    
1275
	foreach ($items as $item) {
1276
		if (isset($found[$item])) {
1277
			continue;
1278
		}
1279

    
1280
		if ($item == 'console') {
1281
			$data[] = $console_line;
1282
		} elseif ($item == 'ttyv0') {
1283
			$data[] = $ttyv0_line;
1284
		} else {
1285
			$data[] = "{$item}\t{$ttyu_line}";
1286
		}
1287
	}
1288

    
1289
	safe_write_file($ttys_file, $data);
1290

    
1291
	unset($ttys, $ttys_file, $ttys_split, $data);
1292

    
1293
	if ($when != "upgrade") {
1294
		reload_ttys();
1295
	}
1296

    
1297
	return;
1298
}
1299

    
1300
function is_serial_enabled() {
1301
	global $g, $config;
1302

    
1303
	if (!isset($g['enableserial_force']) &&
1304
	    !isset($config['system']['enableserial'])) {
1305
		return false;
1306
	}
1307

    
1308
	return true;
1309
}
1310

    
1311
function reload_ttys() {
1312
	// Send a HUP signal to init will make it reload /etc/ttys
1313
	posix_kill(1, SIGHUP);
1314
}
1315

    
1316
function print_value_list($list, $count = 10, $separator = ",") {
1317
	$list = implode($separator, array_slice($list, 0, $count));
1318
	if (count($list) < $count) {
1319
		$list .= ".";
1320
	} else {
1321
		$list .= "...";
1322
	}
1323
	return $list;
1324
}
1325

    
1326
/* DHCP enabled on any interfaces? */
1327
function is_dhcp_server_enabled() {
1328
	global $config;
1329

    
1330
	if (!is_array($config['dhcpd'])) {
1331
		return false;
1332
	}
1333

    
1334
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1335
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1336
			return true;
1337
		}
1338
	}
1339

    
1340
	return false;
1341
}
1342

    
1343
/* DHCP enabled on any interfaces? */
1344
function is_dhcpv6_server_enabled() {
1345
	global $config;
1346

    
1347
	if (is_array($config['interfaces'])) {
1348
		foreach ($config['interfaces'] as $ifcfg) {
1349
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1350
				return true;
1351
			}
1352
		}
1353
	}
1354

    
1355
	if (!is_array($config['dhcpdv6'])) {
1356
		return false;
1357
	}
1358

    
1359
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1360
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1361
			return true;
1362
		}
1363
	}
1364

    
1365
	return false;
1366
}
1367

    
1368
/* radvd enabled on any interfaces? */
1369
function is_radvd_enabled() {
1370
	global $config;
1371

    
1372
	if (!is_array($config['dhcpdv6'])) {
1373
		$config['dhcpdv6'] = array();
1374
	}
1375

    
1376
	$dhcpdv6cfg = $config['dhcpdv6'];
1377
	$Iflist = get_configured_interface_list();
1378

    
1379
	/* handle manually configured DHCP6 server settings first */
1380
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1381
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1382
			continue;
1383
		}
1384

    
1385
		if (!isset($dhcpv6ifconf['ramode'])) {
1386
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1387
		}
1388

    
1389
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1390
			continue;
1391
		}
1392

    
1393
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1394
		if (!is_ipaddrv6($ifcfgipv6)) {
1395
			continue;
1396
		}
1397

    
1398
		return true;
1399
	}
1400

    
1401
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1402
	foreach ($Iflist as $if => $ifdescr) {
1403
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1404
			continue;
1405
		}
1406
		if (!isset($config['interfaces'][$if]['enable'])) {
1407
			continue;
1408
		}
1409

    
1410
		$ifcfgipv6 = get_interface_ipv6($if);
1411
		if (!is_ipaddrv6($ifcfgipv6)) {
1412
			continue;
1413
		}
1414

    
1415
		$ifcfgsnv6 = get_interface_subnetv6($if);
1416
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1417

    
1418
		if (!is_ipaddrv6($subnetv6)) {
1419
			continue;
1420
		}
1421

    
1422
		return true;
1423
	}
1424

    
1425
	return false;
1426
}
1427

    
1428
/* Any PPPoE servers enabled? */
1429
function is_pppoe_server_enabled() {
1430
	global $config;
1431

    
1432
	$pppoeenable = false;
1433

    
1434
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1435
		return false;
1436
	}
1437

    
1438
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1439
		if ($pppoes['mode'] == 'server') {
1440
			$pppoeenable = true;
1441
		}
1442
	}
1443

    
1444
	return $pppoeenable;
1445
}
1446

    
1447
/* Optional arg forces hh:mm:ss without days */
1448
function convert_seconds_to_dhms($sec, $showhoursonly = false) {
1449
	if (!is_numericint($sec)) {
1450
		return '-';
1451
	}
1452
	// FIXME: When we move to PHP 7 we can use "intdiv($sec % X, Y)" etc
1453
	list($d, $h, $m, $s) = array(	(int)($showhoursonly ? 0 : $sec/86400),
1454
					(int)(($showhoursonly ? $sec : $sec % 86400)/3600),
1455
					(int)(($sec % 3600)/60),
1456
					$sec % 60
1457
				);
1458
	return ($d > 0 ? $d . 'd ' : '') . sprintf('%02d:%02d:%02d', $h, $m, $s);
1459
}
1460

    
1461
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1462

    
1463
function get_ppp_uptime($port) {
1464
	if (file_exists("/conf/{$port}.log")) {
1465
		$saved_time = file_get_contents("/conf/{$port}.log");
1466
		$uptime_data = explode("\n", $saved_time);
1467
		$sec = 0;
1468
		foreach ($uptime_data as $upt) {
1469
			$sec += substr($upt, 1 + strpos($upt, " "));
1470
		}
1471
		return convert_seconds_to_dhms($sec);
1472
	} else {
1473
		$total_time = gettext("No history data found!");
1474
		return $total_time;
1475
	}
1476
}
1477

    
1478
//returns interface information
1479
function get_interface_info($ifdescr) {
1480
	global $config, $g;
1481

    
1482
	$ifinfo = array();
1483
	if (empty($config['interfaces'][$ifdescr])) {
1484
		return;
1485
	}
1486
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1487
	$ifinfo['if'] = get_real_interface($ifdescr);
1488

    
1489
	$chkif = $ifinfo['if'];
1490
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1491
	$ifinfo['status'] = $ifinfotmp['status'];
1492
	if (empty($ifinfo['status'])) {
1493
		$ifinfo['status'] = "down";
1494
	}
1495
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1496
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1497
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1498
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1499
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1500
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1501
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1502
	if (isset($ifinfotmp['link0'])) {
1503
		$link0 = "down";
1504
	}
1505
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1506
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1507
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1508
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1509
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1510
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1511

    
1512
	/* Use pfctl for non wrapping 64 bit counters */
1513
	/* Pass */
1514
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1515
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1516
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1517
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1518
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1519
	$in4_pass = $pf_in4_pass[5];
1520
	$out4_pass = $pf_out4_pass[5];
1521
	$in4_pass_packets = $pf_in4_pass[3];
1522
	$out4_pass_packets = $pf_out4_pass[3];
1523
	$in6_pass = $pf_in6_pass[5];
1524
	$out6_pass = $pf_out6_pass[5];
1525
	$in6_pass_packets = $pf_in6_pass[3];
1526
	$out6_pass_packets = $pf_out6_pass[3];
1527
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1528
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1529
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1530
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1531

    
1532
	/* Block */
1533
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1534
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1535
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1536
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1537
	$in4_block = $pf_in4_block[5];
1538
	$out4_block = $pf_out4_block[5];
1539
	$in4_block_packets = $pf_in4_block[3];
1540
	$out4_block_packets = $pf_out4_block[3];
1541
	$in6_block = $pf_in6_block[5];
1542
	$out6_block = $pf_out6_block[5];
1543
	$in6_block_packets = $pf_in6_block[3];
1544
	$out6_block_packets = $pf_out6_block[3];
1545
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1546
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1547
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1548
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1549

    
1550
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1551
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1552
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1553
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1554

    
1555
	$ifconfiginfo = "";
1556
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1557
	switch ($link_type) {
1558
		/* DHCP? -> see if dhclient is up */
1559
		case "dhcp":
1560
			/* see if dhclient is up */
1561
			if (find_dhclient_process($ifinfo['if']) != 0) {
1562
				$ifinfo['dhcplink'] = "up";
1563
			} else {
1564
				$ifinfo['dhcplink'] = "down";
1565
			}
1566

    
1567
			break;
1568
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1569
		case "pppoe":
1570
		case "pptp":
1571
		case "l2tp":
1572
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1573
				/* get PPPoE link status for dial on demand */
1574
				$ifinfo["{$link_type}link"] = "up";
1575
			} else {
1576
				$ifinfo["{$link_type}link"] = "down";
1577
			}
1578

    
1579
			break;
1580
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1581
		case "ppp":
1582
			if ($ifinfo['status'] == "up") {
1583
				$ifinfo['ppplink'] = "up";
1584
			} else {
1585
				$ifinfo['ppplink'] = "down" ;
1586
			}
1587

    
1588
			if (empty($ifinfo['status'])) {
1589
				$ifinfo['status'] = "down";
1590
			}
1591

    
1592
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1593
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1594
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1595
						break;
1596
					}
1597
				}
1598
			}
1599
			$dev = $ppp['ports'];
1600
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1601
				break;
1602
			}
1603
			if (!file_exists($dev)) {
1604
				$ifinfo['nodevice'] = 1;
1605
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1606
			}
1607

    
1608
			$usbmodemoutput = array();
1609
			exec("/usr/sbin/usbconfig", $usbmodemoutput);
1610
			$mondev = "{$g['tmp_path']}/3gstats.{$ifdescr}";
1611
			if (file_exists($mondev)) {
1612
				$cellstats = file($mondev);
1613
				/* skip header */
1614
				$a_cellstats = explode(",", $cellstats[1]);
1615
				if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
1616
					$ifinfo['cell_rssi'] = huawei_rssi_to_string($a_cellstats[1]);
1617
					$ifinfo['cell_mode'] = huawei_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1618
					$ifinfo['cell_simstate'] = huawei_simstate_to_string($a_cellstats[10]);
1619
					$ifinfo['cell_service'] = huawei_service_to_string(trim($a_cellstats[11]));
1620
				}
1621
				if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
1622
					$ifinfo['cell_rssi'] = zte_rssi_to_string($a_cellstats[1]);
1623
					$ifinfo['cell_mode'] = zte_mode_to_string($a_cellstats[2], $a_cellstats[3]);
1624
					$ifinfo['cell_simstate'] = zte_simstate_to_string($a_cellstats[10]);
1625
					$ifinfo['cell_service'] = zte_service_to_string(trim($a_cellstats[11]));
1626
				}
1627
				$ifinfo['cell_upstream'] = $a_cellstats[4];
1628
				$ifinfo['cell_downstream'] = trim($a_cellstats[5]);
1629
				$ifinfo['cell_sent'] = $a_cellstats[6];
1630
				$ifinfo['cell_received'] = trim($a_cellstats[7]);
1631
				$ifinfo['cell_bwupstream'] = $a_cellstats[8];
1632
				$ifinfo['cell_bwdownstream'] = trim($a_cellstats[9]);
1633
			}
1634
			// Calculate cumulative uptime for PPP link. Useful for connections that have per minute/hour contracts so you don't go over!
1635
			if (isset($ppp['uptime'])) {
1636
				$ifinfo['ppp_uptime_accumulated'] = "(".get_ppp_uptime($ifinfo['if']).")";
1637
			}
1638
			break;
1639
		default:
1640
			break;
1641
	}
1642

    
1643
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1644
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1645
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1646
	}
1647

    
1648
	if ($ifinfo['status'] == "up") {
1649
		/* try to determine media with ifconfig */
1650
		unset($ifconfiginfo);
1651
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1652
		$wifconfiginfo = array();
1653
		if (is_interface_wireless($ifdescr)) {
1654
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1655
			array_shift($wifconfiginfo);
1656
		}
1657
		$matches = "";
1658
		foreach ($ifconfiginfo as $ici) {
1659

    
1660
			/* don't list media/speed for wireless cards, as it always
1661
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1662
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1663
				$ifinfo['media'] = $matches[1];
1664
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1665
				$ifinfo['media'] = $matches[1];
1666
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1667
				$ifinfo['media'] = $matches[1];
1668
			}
1669

    
1670
			if (preg_match("/status: (.*)$/", $ici, $matches)) {
1671
				if ($matches[1] != "active") {
1672
					$ifinfo['status'] = $matches[1];
1673
				}
1674
				if ($ifinfo['status'] == gettext("running")) {
1675
					$ifinfo['status'] = gettext("up");
1676
				}
1677
			}
1678
			if (preg_match("/channel (\S*)/", $ici, $matches)) {
1679
				$ifinfo['channel'] = $matches[1];
1680
			}
1681
			if (preg_match("/ssid (\".*?\"|\S*)/", $ici, $matches)) {
1682
				if ($matches[1][0] == '"') {
1683
					$ifinfo['ssid'] = substr($matches[1], 1, -1);
1684
				}
1685
				else {
1686
					$ifinfo['ssid'] = $matches[1];
1687
				}
1688
			}
1689
			if (preg_match("/laggproto (.*)$/", $ici, $matches)) {
1690
				$ifinfo['laggproto'] = $matches[1];
1691
			}
1692
			if (preg_match("/laggport: (.*)$/", $ici, $matches)) {
1693
				$ifinfo['laggport'][] = $matches[1];
1694
			}
1695
		}
1696
		foreach ($wifconfiginfo as $ici) {
1697
			$elements = preg_split("/[ ]+/i", $ici);
1698
			if ($elements[0] != "") {
1699
				$ifinfo['bssid'] = $elements[0];
1700
			}
1701
			if ($elements[3] != "") {
1702
				$ifinfo['rate'] = $elements[3];
1703
			}
1704
			if ($elements[4] != "") {
1705
				$ifinfo['rssi'] = $elements[4];
1706
			}
1707
		}
1708
		/* lookup the gateway */
1709
		if (interface_has_gateway($ifdescr)) {
1710
			$ifinfo['gateway'] = get_interface_gateway($ifdescr);
1711
			$ifinfo['gatewayv6'] = get_interface_gateway_v6($ifdescr);
1712
		}
1713
	}
1714

    
1715
	$bridge = "";
1716
	$bridge = link_interface_to_bridge($ifdescr);
1717
	if ($bridge) {
1718
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1719
		if (stristr($bridge_text, "blocking") <> false) {
1720
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1721
			$ifinfo['bridgeint'] = $bridge;
1722
		} else if (stristr($bridge_text, "learning") <> false) {
1723
			$ifinfo['bridge'] = gettext("learning");
1724
			$ifinfo['bridgeint'] = $bridge;
1725
		} else if (stristr($bridge_text, "forwarding") <> false) {
1726
			$ifinfo['bridge'] = gettext("forwarding");
1727
			$ifinfo['bridgeint'] = $bridge;
1728
		}
1729
	}
1730

    
1731
	return $ifinfo;
1732
}
1733

    
1734
//returns cpu speed of processor. Good for determining capabilities of machine
1735
function get_cpu_speed() {
1736
	return get_single_sysctl("hw.clockrate");
1737
}
1738

    
1739
function get_uptime_sec() {
1740
	$boottime = "";
1741
	$matches = "";
1742
	$boottime = get_single_sysctl("kern.boottime");
1743
	preg_match("/sec = (\d+)/", $boottime, $matches);
1744
	$boottime = $matches[1];
1745
	if (intval($boottime) == 0) {
1746
		return 0;
1747
	}
1748

    
1749
	$uptime = time() - $boottime;
1750
	return $uptime;
1751
}
1752

    
1753
function add_hostname_to_watch($hostname) {
1754
	if (!is_dir("/var/db/dnscache")) {
1755
		mkdir("/var/db/dnscache");
1756
	}
1757
	$result = array();
1758
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1759
		$domrecords = array();
1760
		$domips = array();
1761
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1762
		if ($rethost == 0) {
1763
			foreach ($domrecords as $domr) {
1764
				$doml = explode(" ", $domr);
1765
				$domip = $doml[3];
1766
				/* fill array with domain ip addresses */
1767
				if (is_ipaddr($domip)) {
1768
					$domips[] = $domip;
1769
				}
1770
			}
1771
		}
1772
		sort($domips);
1773
		$contents = "";
1774
		if (!empty($domips)) {
1775
			foreach ($domips as $ip) {
1776
				$contents .= "$ip\n";
1777
			}
1778
		}
1779
		file_put_contents("/var/db/dnscache/$hostname", $contents);
1780
		/* Remove empty elements */
1781
		$result = array_filter(explode("\n", $contents), 'strlen');
1782
	}
1783
	return $result;
1784
}
1785

    
1786
function is_fqdn($fqdn) {
1787
	$hostname = false;
1788
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1789
		$hostname = true;
1790
	}
1791
	if (preg_match("/\.\./", $fqdn)) {
1792
		$hostname = false;
1793
	}
1794
	if (preg_match("/^\./i", $fqdn)) {
1795
		$hostname = false;
1796
	}
1797
	if (preg_match("/\//i", $fqdn)) {
1798
		$hostname = false;
1799
	}
1800
	return($hostname);
1801
}
1802

    
1803
function pfsense_default_state_size() {
1804
	/* get system memory amount */
1805
	$memory = get_memory();
1806
	$physmem = $memory[0];
1807
	/* Be cautious and only allocate 10% of system memory to the state table */
1808
	$max_states = (int) ($physmem/10)*1000;
1809
	return $max_states;
1810
}
1811

    
1812
function pfsense_default_tables_size() {
1813
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1814
	return $current;
1815
}
1816

    
1817
function pfsense_default_table_entries_size() {
1818
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1819
	return (trim($current));
1820
}
1821

    
1822
/* Compare the current hostname DNS to the DNS cache we made
1823
 * if it has changed we return the old records
1824
 * if no change we return false */
1825
function compare_hostname_to_dnscache($hostname) {
1826
	if (!is_dir("/var/db/dnscache")) {
1827
		mkdir("/var/db/dnscache");
1828
	}
1829
	$hostname = trim($hostname);
1830
	if (is_readable("/var/db/dnscache/{$hostname}")) {
1831
		$oldcontents = file_get_contents("/var/db/dnscache/{$hostname}");
1832
	} else {
1833
		$oldcontents = "";
1834
	}
1835
	if ((is_fqdn($hostname)) && (!is_ipaddr($hostname))) {
1836
		$domrecords = array();
1837
		$domips = array();
1838
		exec("/usr/bin/host -t A " . escapeshellarg($hostname), $domrecords, $rethost);
1839
		if ($rethost == 0) {
1840
			foreach ($domrecords as $domr) {
1841
				$doml = explode(" ", $domr);
1842
				$domip = $doml[3];
1843
				/* fill array with domain ip addresses */
1844
				if (is_ipaddr($domip)) {
1845
					$domips[] = $domip;
1846
				}
1847
			}
1848
		}
1849
		sort($domips);
1850
		$contents = "";
1851
		if (!empty($domips)) {
1852
			foreach ($domips as $ip) {
1853
				$contents .= "$ip\n";
1854
			}
1855
		}
1856
	}
1857

    
1858
	if (trim($oldcontents) != trim($contents)) {
1859
		if ($g['debug']) {
1860
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1861
		}
1862
		return ($oldcontents);
1863
	} else {
1864
		return false;
1865
	}
1866
}
1867

    
1868
/*
1869
 * load_crypto() - Load crypto modules if enabled in config.
1870
 */
1871
function load_crypto() {
1872
	global $config, $g;
1873
	$crypto_modules = array('aesni', 'cryptodev');
1874

    
1875
	if (!in_array($config['system']['crypto_hardware'], $crypto_modules)) {
1876
		return false;
1877
	}
1878

    
1879
	if (!empty($config['system']['crypto_hardware']) && !is_module_loaded($config['system']['crypto_hardware'])) {
1880
		log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $config['system']['crypto_hardware']));
1881
		mwexec("/sbin/kldload {$config['system']['crypto_hardware']}");
1882
	}
1883
}
1884

    
1885
/*
1886
 * load_thermal_hardware() - Load temperature monitor kernel module
1887
 */
1888
function load_thermal_hardware() {
1889
	global $config, $g;
1890
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1891

    
1892
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1893
		return false;
1894
	}
1895

    
1896
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1897
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1898
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1899
	}
1900
}
1901

    
1902
/****f* pfsense-utils/isvm
1903
 * NAME
1904
 *   isvm
1905
 * INPUTS
1906
 *	none
1907
 * RESULT
1908
 *   returns true if machine is running under a virtual environment
1909
 ******/
1910
function isvm() {
1911
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
1912
	$_gb = exec('/bin/kenv -q smbios.system.product 2>/dev/null', $output, $rc);
1913

    
1914
	if ($rc != 0 || !isset($output[0])) {
1915
		return false;
1916
	}
1917

    
1918
	foreach ($virtualenvs as $virtualenv) {
1919
		if (stripos($output[0], $virtualenv) !== false) {
1920
			return true;
1921
		}
1922
	}
1923

    
1924
	return false;
1925
}
1926

    
1927
function get_freebsd_version() {
1928
	$version = explode(".", php_uname("r"));
1929
	return $version[0];
1930
}
1931

    
1932
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
1933
	global $config, $g;
1934

    
1935
	$fp = fopen($destination, "wb");
1936

    
1937
	if (!$fp) {
1938
		return false;
1939
	}
1940

    
1941
	$ch = curl_init();
1942
	curl_setopt($ch, CURLOPT_URL, $url);
1943
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
1944
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1945
	curl_setopt($ch, CURLOPT_FILE, $fp);
1946
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1947
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1948
	curl_setopt($ch, CURLOPT_HEADER, false);
1949
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1950
	if (!isset($config['system']['do_not_send_uniqueid'])) {
1951
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
1952
	} else {
1953
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1954
	}
1955

    
1956
	if (!empty($config['system']['proxyurl'])) {
1957
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1958
		if (!empty($config['system']['proxyport'])) {
1959
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1960
		}
1961
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1962
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1963
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1964
		}
1965
	}
1966

    
1967
	@curl_exec($ch);
1968
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1969
	fclose($fp);
1970
	curl_close($ch);
1971
	if ($http_code == 200) {
1972
		return true;
1973
	} else {
1974
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
1975
		unlink_if_exists($destination);
1976
		return false;
1977
	}
1978
}
1979

    
1980
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
1981
	global $config, $g;
1982
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
1983
	$file_size = 1;
1984
	$downloaded = 1;
1985
	$first_progress_update = TRUE;
1986
	/* open destination file */
1987
	$fout = fopen($destination, "wb");
1988

    
1989
	if (!$fout) {
1990
		return false;
1991
	}
1992
	/*
1993
	 *      Originally by Author: Keyvan Minoukadeh
1994
	 *      Modified by Scott Ullrich to return Content-Length size
1995
	 */
1996
	$ch = curl_init();
1997
	curl_setopt($ch, CURLOPT_URL, $url);
1998
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
1999
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2000
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
2001
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2002
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
2003
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
2004
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2005
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2006
	if (!isset($config['system']['do_not_send_uniqueid'])) {
2007
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
2008
	} else {
2009
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2010
	}
2011

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

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

    
2036
function read_header($ch, $string) {
2037
	global $file_size, $fout;
2038
	$length = strlen($string);
2039
	$regs = "";
2040
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
2041
	if ($regs[2] <> "") {
2042
		$file_size = intval($regs[2]);
2043
	}
2044
	ob_flush();
2045
	return $length;
2046
}
2047

    
2048
function read_body($ch, $string) {
2049
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
2050
	global $pkg_interface;
2051
	$length = strlen($string);
2052
	$downloaded += intval($length);
2053
	if ($file_size > 0) {
2054
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
2055
		$downloadProgress = 100 - $downloadProgress;
2056
	} else {
2057
		$downloadProgress = 0;
2058
	}
2059
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
2060
		if ($sendto == "status") {
2061
			if ($pkg_interface == "console") {
2062
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2063
					$tostatus = $static_status . $downloadProgress . "%";
2064
					if ($downloadProgress == 100) {
2065
						$tostatus = $tostatus . "\r";
2066
					}
2067
					update_status($tostatus);
2068
				}
2069
			} else {
2070
				$tostatus = $static_status . $downloadProgress . "%";
2071
				update_status($tostatus);
2072
			}
2073
		} else {
2074
			if ($pkg_interface == "console") {
2075
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2076
					$tooutput = $static_output . $downloadProgress . "%";
2077
					if ($downloadProgress == 100) {
2078
						$tooutput = $tooutput . "\r";
2079
					}
2080
					update_output_window($tooutput);
2081
				}
2082
			} else {
2083
				$tooutput = $static_output . $downloadProgress . "%";
2084
				update_output_window($tooutput);
2085
			}
2086
		}
2087
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
2088
			update_progress_bar($downloadProgress, $first_progress_update);
2089
			$first_progress_update = FALSE;
2090
		}
2091
		$lastseen = $downloadProgress;
2092
	}
2093
	if ($fout) {
2094
		fwrite($fout, $string);
2095
	}
2096
	ob_flush();
2097
	return $length;
2098
}
2099

    
2100
/*
2101
 *   update_output_window: update bottom textarea dynamically.
2102
 */
2103
function update_output_window($text) {
2104
	global $pkg_interface;
2105
	$log = preg_replace("/\n/", "\\n", $text);
2106
	if ($pkg_interface != "console") {
2107
?>
2108
<script type="text/javascript">
2109
//<![CDATA[
2110
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
2111
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
2112
//]]>
2113
</script>
2114
<?php
2115
	}
2116
	/* ensure that contents are written out */
2117
	ob_flush();
2118
}
2119

    
2120
/*
2121
 *   update_status: update top textarea dynamically.
2122
 */
2123
function update_status($status) {
2124
	global $pkg_interface;
2125

    
2126
	if ($pkg_interface == "console") {
2127
		print ("{$status}");
2128
	}
2129

    
2130
	/* ensure that contents are written out */
2131
	ob_flush();
2132
}
2133

    
2134
/*
2135
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
2136
 */
2137
function update_progress_bar($percent, $first_time) {
2138
	global $pkg_interface;
2139
	if ($percent > 100) {
2140
		$percent = 1;
2141
	}
2142
	if ($pkg_interface <> "console") {
2143
		echo '<script type="text/javascript">';
2144
		echo "\n//<![CDATA[\n";
2145
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
2146
		echo "\n//]]>\n";
2147
		echo '</script>';
2148
	} else {
2149
		if (!($first_time)) {
2150
			echo "\x08\x08\x08\x08\x08";
2151
		}
2152
		echo sprintf("%4d%%", $percent);
2153
	}
2154
}
2155

    
2156
function update_alias_name($new_alias_name, $orig_alias_name) {
2157
	if (!$orig_alias_name) {
2158
		return;
2159
	}
2160

    
2161
	// Firewall rules
2162
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2163
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2164
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2165
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2166
	// NAT Rules
2167
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2168
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2169
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2170
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2171
	update_alias_names_upon_change(array('nat', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2172
	update_alias_names_upon_change(array('nat', 'rule'), array('local-port'), $new_alias_name, $orig_alias_name);
2173
	// NAT 1:1 Rules
2174
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('external'), $new_alias_name, $orig_alias_name);
2175
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2176
	update_alias_names_upon_change(array('nat', 'onetoone'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2177
	// NAT Outbound Rules
2178
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('source', 'network'), $new_alias_name, $orig_alias_name);
2179
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('sourceport'), $new_alias_name, $orig_alias_name);
2180
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2181
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('dstport'), $new_alias_name, $orig_alias_name);
2182
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2183
	// Alias in an alias
2184
	update_alias_names_upon_change(array('aliases', 'alias'), array('address'), $new_alias_name, $orig_alias_name);
2185
}
2186

    
2187
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2188
	global $g, $config, $pconfig, $debug;
2189
	if (!$origname) {
2190
		return;
2191
	}
2192

    
2193
	$sectionref = &$config;
2194
	foreach ($section as $sectionname) {
2195
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2196
			$sectionref = &$sectionref[$sectionname];
2197
		} else {
2198
			return;
2199
		}
2200
	}
2201

    
2202
	if ($debug) {
2203
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2204
		fwrite($fd, print_r($pconfig, true));
2205
	}
2206

    
2207
	if (is_array($sectionref)) {
2208
		foreach ($sectionref as $itemkey => $item) {
2209
			if ($debug) {
2210
				fwrite($fd, "$itemkey\n");
2211
			}
2212

    
2213
			$fieldfound = true;
2214
			$fieldref = &$sectionref[$itemkey];
2215
			foreach ($field as $fieldname) {
2216
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2217
					$fieldref = &$fieldref[$fieldname];
2218
				} else {
2219
					$fieldfound = false;
2220
					break;
2221
				}
2222
			}
2223
			if ($fieldfound && $fieldref == $origname) {
2224
				if ($debug) {
2225
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2226
				}
2227
				$fieldref = $new_alias_name;
2228
			}
2229
		}
2230
	}
2231

    
2232
	if ($debug) {
2233
		fclose($fd);
2234
	}
2235

    
2236
}
2237

    
2238
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2239
	/*
2240
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2241
	 * $type = if set to 'url' then subnets and ips will be returned,
2242
	 *         if set to 'url_ports' port-ranges and ports will be returned
2243
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2244
	 *
2245
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2246
	 */
2247

    
2248
	if (!file_exists($filename)) {
2249
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2250
		return null;
2251
	}
2252

    
2253
	if (filesize($filename) == 0) {
2254
		log_error(sprintf(gettext("Could not process empty file from alias: %s"), $filename));
2255
		return null;
2256
	}
2257
	$fd = @fopen($filename, 'r');
2258
	if (!$fd) {
2259
		log_error(sprintf(gettext("Could not process aliases from alias: %s"), $filename));
2260
		return null;
2261
	}
2262
	$items = array();
2263
	$comments = array();
2264
	/* NOTE: fgetss() is not a typo RTFM before being smart */
2265
	while (($fc = fgetss($fd)) !== FALSE) {
2266
		$tmp = trim($fc, " \t\n\r");
2267
		if (empty($tmp)) {
2268
			continue;
2269
		}
2270
		if (($kflc) && (strpos($tmp, '#') === 0)) {	// Keep Full Line Comments (lines beginning with #).
2271
			$comments[] = $tmp;
2272
		} else {
2273
			$tmp_str = strstr($tmp, '#', true);
2274
			if (!empty($tmp_str)) {
2275
				$tmp = $tmp_str;
2276
			}
2277
			$tmp_str = strstr($tmp, ' ', true);
2278
			if (!empty($tmp_str)) {
2279
				$tmp = $tmp_str;
2280
			}
2281
			$valid = (($type == "url" || $type == "urltable") && (is_ipaddr($tmp) || is_subnet($tmp))) ||
2282
				(($type == "url_ports" || $type == "urltable_ports") && is_port_or_range($tmp));
2283
			if ($valid) {
2284
				$items[] = $tmp;
2285
				if (count($items) == $max_items) {
2286
					break;
2287
				}
2288
			}
2289
		}
2290
	}
2291
	fclose($fd);
2292
	return array_merge($comments, $items);
2293
}
2294

    
2295
function update_alias_url_data() {
2296
	global $config, $g;
2297

    
2298
	$updated = false;
2299

    
2300
	/* item is a url type */
2301
	$lockkey = lock('aliasurl');
2302
	if (is_array($config['aliases']['alias'])) {
2303
		foreach ($config['aliases']['alias'] as $x => $alias) {
2304
			if (empty($alias['aliasurl'])) {
2305
				continue;
2306
			}
2307

    
2308
			$address = null;
2309
			foreach ($alias['aliasurl'] as $alias_url) {
2310
				/* fetch down and add in */
2311
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2312
				unlink($temp_filename);
2313
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2314
				mkdir($temp_filename);
2315
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2316
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2317
					continue;
2318
				}
2319

    
2320
				/* if the item is tar gzipped then extract */
2321
				if (stripos($alias_url, '.tgz')) {
2322
					if (!process_alias_tgz($temp_filename)) {
2323
						continue;
2324
					}
2325
				}
2326
				if (file_exists("{$temp_filename}/aliases")) {
2327
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2328
					mwexec("/bin/rm -rf {$temp_filename}");
2329
				}
2330
			}
2331
			if ($address != null) {
2332
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2333
				$updated = true;
2334
			}
2335
		}
2336
	}
2337
	unlock($lockkey);
2338

    
2339
	/* Report status to callers as well */
2340
	return $updated;
2341
}
2342

    
2343
function process_alias_tgz($temp_filename) {
2344
	if (!file_exists('/usr/bin/tar')) {
2345
		log_error(gettext("Alias archive is a .tar/tgz file which cannot be decompressed because utility is missing!"));
2346
		return false;
2347
	}
2348
	rename("{$temp_filename}/aliases", "{$temp_filename}/aliases.tgz");
2349
	mwexec("/usr/bin/tar xzf {$temp_filename}/aliases.tgz -C {$temp_filename}/aliases/");
2350
	unlink("{$temp_filename}/aliases.tgz");
2351
	$files_to_process = return_dir_as_array("{$temp_filename}/");
2352
	/* foreach through all extracted files and build up aliases file */
2353
	$fd = @fopen("{$temp_filename}/aliases", "w");
2354
	if (!$fd) {
2355
		log_error(sprintf(gettext("Could not open %s/aliases for writing!"), $temp_filename));
2356
		return false;
2357
	}
2358
	foreach ($files_to_process as $f2p) {
2359
		$tmpfd = @fopen($f2p, 'r');
2360
		if (!$tmpfd) {
2361
			log_error(sprintf(gettext('The following file could not be read %1$s from %2$s'), $f2p, $temp_filename));
2362
			continue;
2363
		}
2364
		while (($tmpbuf = fread($tmpfd, 65536)) !== FALSE) {
2365
			fwrite($fd, $tmpbuf);
2366
		}
2367
		fclose($tmpfd);
2368
		unlink($f2p);
2369
	}
2370
	fclose($fd);
2371
	unset($tmpbuf);
2372

    
2373
	return true;
2374
}
2375

    
2376
function version_compare_dates($a, $b) {
2377
	$a_time = strtotime($a);
2378
	$b_time = strtotime($b);
2379

    
2380
	if ((!$a_time) || (!$b_time)) {
2381
		return FALSE;
2382
	} else {
2383
		if ($a_time < $b_time) {
2384
			return -1;
2385
		} elseif ($a_time == $b_time) {
2386
			return 0;
2387
		} else {
2388
			return 1;
2389
		}
2390
	}
2391
}
2392
function version_get_string_value($a) {
2393
	$strs = array(
2394
		0 => "ALPHA-ALPHA",
2395
		2 => "ALPHA",
2396
		3 => "BETA",
2397
		4 => "B",
2398
		5 => "C",
2399
		6 => "D",
2400
		7 => "RC",
2401
		8 => "RELEASE",
2402
		9 => "*"			// Matches all release levels
2403
	);
2404
	$major = 0;
2405
	$minor = 0;
2406
	foreach ($strs as $num => $str) {
2407
		if (substr($a, 0, strlen($str)) == $str) {
2408
			$major = $num;
2409
			$n = substr($a, strlen($str));
2410
			if (is_numeric($n)) {
2411
				$minor = $n;
2412
			}
2413
			break;
2414
		}
2415
	}
2416
	return "{$major}.{$minor}";
2417
}
2418
function version_compare_string($a, $b) {
2419
	// Only compare string parts if both versions give a specific release
2420
	// (If either version lacks a string part, assume intended to match all release levels)
2421
	if (isset($a) && isset($b)) {
2422
		return version_compare_numeric(version_get_string_value($a), version_get_string_value($b));
2423
	} else {
2424
		return 0;
2425
	}
2426
}
2427
function version_compare_numeric($a, $b) {
2428
	$a_arr = explode('.', rtrim($a, '.'));
2429
	$b_arr = explode('.', rtrim($b, '.'));
2430

    
2431
	foreach ($a_arr as $n => $val) {
2432
		if (array_key_exists($n, $b_arr)) {
2433
			// So far so good, both have values at this minor version level. Compare.
2434
			if ($val > $b_arr[$n]) {
2435
				return 1;
2436
			} elseif ($val < $b_arr[$n]) {
2437
				return -1;
2438
			}
2439
		} else {
2440
			// a is greater, since b doesn't have any minor version here.
2441
			return 1;
2442
		}
2443
	}
2444
	if (count($b_arr) > count($a_arr)) {
2445
		// b is longer than a, so it must be greater.
2446
		return -1;
2447
	} else {
2448
		// Both a and b are of equal length and value.
2449
		return 0;
2450
	}
2451
}
2452
function pfs_version_compare($cur_time, $cur_text, $remote) {
2453
	// First try date compare
2454
	$v = version_compare_dates($cur_time, $remote);
2455
	if ($v === FALSE) {
2456
		// If that fails, try to compare by string
2457
		// Before anything else, simply test if the strings are equal
2458
		if (($cur_text == $remote) || ($cur_time == $remote)) {
2459
			return 0;
2460
		}
2461
		list($cur_num, $cur_str) = explode('-', $cur_text);
2462
		list($rem_num, $rem_str) = explode('-', $remote);
2463

    
2464
		// First try to compare the numeric parts of the version string.
2465
		$v = version_compare_numeric($cur_num, $rem_num);
2466

    
2467
		// If the numeric parts are the same, compare the string parts.
2468
		if ($v == 0) {
2469
			return version_compare_string($cur_str, $rem_str);
2470
		}
2471
	}
2472
	return $v;
2473
}
2474
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2475
	global $g, $config;
2476

    
2477
	$urltable_prefix = "/var/db/aliastables/";
2478
	$urltable_filename = $urltable_prefix . $name . ".txt";
2479
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2480

    
2481
	// Make the aliases directory if it doesn't exist
2482
	if (!file_exists($urltable_prefix)) {
2483
		mkdir($urltable_prefix);
2484
	} elseif (!is_dir($urltable_prefix)) {
2485
		unlink($urltable_prefix);
2486
		mkdir($urltable_prefix);
2487
	}
2488

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

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

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

    
2503
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2504
			if ($type == "urltable_ports") {
2505
				$parsed_contents = group_ports($parsed_contents, true);
2506
			}
2507
			if (is_array($parsed_contents)) {
2508
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2509
			} else {
2510
				touch($urltable_filename);
2511
			}
2512

    
2513
			/* Remove existing archive and create an up to date archive if RAM disk is enabled. */
2514
			unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz");
2515
			if (isset($config['system']['use_mfs_tmpvar'])) {
2516
				mwexec("/usr/bin/tar -czf " . escapeshellarg("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz") . " -C / " . escapeshellarg($urltable_filename));
2517
			}
2518

    
2519
			unlink_if_exists($tmp_urltable_filename);
2520
		} else {
2521
			if (!$validateonly) {
2522
				touch($urltable_filename);
2523
			}
2524
			return false;
2525
		}
2526
		return true;
2527
	} else {
2528
		// File exists, and it doesn't need to be updated.
2529
		return -1;
2530
	}
2531
}
2532

    
2533
function get_include_contents($filename) {
2534
	if (is_file($filename)) {
2535
		ob_start();
2536
		include $filename;
2537
		$contents = ob_get_contents();
2538
		ob_end_clean();
2539
		return $contents;
2540
	}
2541
	return false;
2542
}
2543

    
2544
/* This xml 2 array function is courtesy of the php.net comment section on xml_parse.
2545
 * it is roughly 4 times faster then our existing pfSense parser but due to the large
2546
 * size of the RRD xml dumps this is required.
2547
 * The reason we do not use it for pfSense is that it does not know about array fields
2548
 * which causes it to fail on array fields with single items. Possible Todo?
2549
 */
2550
function xml2array($contents, $get_attributes = 1, $priority = 'tag') {
2551
	if (!function_exists('xml_parser_create')) {
2552
		return array ();
2553
	}
2554
	$parser = xml_parser_create('');
2555
	xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8");
2556
	xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
2557
	xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
2558
	xml_parse_into_struct($parser, trim($contents), $xml_values);
2559
	xml_parser_free($parser);
2560
	if (!$xml_values) {
2561
		return; //Hmm...
2562
	}
2563
	$xml_array = array ();
2564
	$parents = array ();
2565
	$opened_tags = array ();
2566
	$arr = array ();
2567
	$current = & $xml_array;
2568
	$repeated_tag_index = array ();
2569
	foreach ($xml_values as $data) {
2570
		unset ($attributes, $value);
2571
		extract($data);
2572
		$result = array ();
2573
		$attributes_data = array ();
2574
		if (isset ($value)) {
2575
			if ($priority == 'tag') {
2576
				$result = $value;
2577
			} else {
2578
				$result['value'] = $value;
2579
			}
2580
		}
2581
		if (isset ($attributes) and $get_attributes) {
2582
			foreach ($attributes as $attr => $val) {
2583
				if ($priority == 'tag') {
2584
					$attributes_data[$attr] = $val;
2585
				} else {
2586
					$result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
2587
				}
2588
			}
2589
		}
2590
		if ($type == "open") {
2591
			$parent[$level -1] = & $current;
2592
			if (!is_array($current) or (!in_array($tag, array_keys($current)))) {
2593
				$current[$tag] = $result;
2594
				if ($attributes_data) {
2595
					$current[$tag . '_attr'] = $attributes_data;
2596
				}
2597
				$repeated_tag_index[$tag . '_' . $level] = 1;
2598
				$current = & $current[$tag];
2599
			} else {
2600
				if (isset ($current[$tag][0])) {
2601
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2602
					$repeated_tag_index[$tag . '_' . $level]++;
2603
				} else {
2604
					$current[$tag] = array (
2605
						$current[$tag],
2606
						$result
2607
						);
2608
					$repeated_tag_index[$tag . '_' . $level] = 2;
2609
					if (isset ($current[$tag . '_attr'])) {
2610
						$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2611
						unset ($current[$tag . '_attr']);
2612
					}
2613
				}
2614
				$last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
2615
				$current = & $current[$tag][$last_item_index];
2616
			}
2617
		} elseif ($type == "complete") {
2618
			if (!isset ($current[$tag])) {
2619
				$current[$tag] = $result;
2620
				$repeated_tag_index[$tag . '_' . $level] = 1;
2621
				if ($priority == 'tag' and $attributes_data) {
2622
					$current[$tag . '_attr'] = $attributes_data;
2623
				}
2624
			} else {
2625
				if (isset ($current[$tag][0]) and is_array($current[$tag])) {
2626
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2627
					if ($priority == 'tag' and $get_attributes and $attributes_data) {
2628
						$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2629
					}
2630
					$repeated_tag_index[$tag . '_' . $level]++;
2631
				} else {
2632
					$current[$tag] = array (
2633
						$current[$tag],
2634
						$result
2635
						);
2636
					$repeated_tag_index[$tag . '_' . $level] = 1;
2637
					if ($priority == 'tag' and $get_attributes) {
2638
						if (isset ($current[$tag . '_attr'])) {
2639
							$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2640
							unset ($current[$tag . '_attr']);
2641
						}
2642
						if ($attributes_data) {
2643
							$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2644
						}
2645
					}
2646
					$repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
2647
				}
2648
			}
2649
		} elseif ($type == 'close') {
2650
			$current = & $parent[$level -1];
2651
		}
2652
	}
2653
	return ($xml_array);
2654
}
2655

    
2656
function get_country_name($country_code) {
2657
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2658
		return "";
2659
	}
2660

    
2661
	$country_names_xml = "/usr/local/share/pfSense/iso_3166-1_list_en.xml";
2662
	$country_names_contents = file_get_contents($country_names_xml);
2663
	$country_names = xml2array($country_names_contents);
2664

    
2665
	if ($country_code == "ALL") {
2666
		$country_list = array();
2667
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2668
			$country_list[] = array(
2669
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2670
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2671
		}
2672
		return $country_list;
2673
	}
2674

    
2675
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2676
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2677
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2678
		}
2679
	}
2680
	return "";
2681
}
2682

    
2683
/* sort by interface only, retain the original order of rules that apply to
2684
   the same interface */
2685
function filter_rules_sort() {
2686
	global $config;
2687

    
2688
	/* mark each rule with the sequence number (to retain the order while sorting) */
2689
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2690
		$config['filter']['rule'][$i]['seq'] = $i;
2691
	}
2692

    
2693
	usort($config['filter']['rule'], "filter_rules_compare");
2694

    
2695
	/* strip the sequence numbers again */
2696
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2697
		unset($config['filter']['rule'][$i]['seq']);
2698
	}
2699
}
2700
function filter_rules_compare($a, $b) {
2701
	if (isset($a['floating']) && isset($b['floating'])) {
2702
		return $a['seq'] - $b['seq'];
2703
	} else if (isset($a['floating'])) {
2704
		return -1;
2705
	} else if (isset($b['floating'])) {
2706
		return 1;
2707
	} else if ($a['interface'] == $b['interface']) {
2708
		return $a['seq'] - $b['seq'];
2709
	} else {
2710
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2711
	}
2712
}
2713

    
2714
function generate_ipv6_from_mac($mac) {
2715
	$elements = explode(":", $mac);
2716
	if (count($elements) <> 6) {
2717
		return false;
2718
	}
2719

    
2720
	$i = 0;
2721
	$ipv6 = "fe80::";
2722
	foreach ($elements as $byte) {
2723
		if ($i == 0) {
2724
			$hexadecimal = substr($byte, 1, 2);
2725
			$bitmap = base_convert($hexadecimal, 16, 2);
2726
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2727
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2728
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2729
		}
2730
		$ipv6 .= $byte;
2731
		if ($i == 1) {
2732
			$ipv6 .= ":";
2733
		}
2734
		if ($i == 3) {
2735
			$ipv6 .= ":";
2736
		}
2737
		if ($i == 2) {
2738
			$ipv6 .= "ff:fe";
2739
		}
2740

    
2741
		$i++;
2742
	}
2743
	return $ipv6;
2744
}
2745

    
2746
/****f* pfsense-utils/load_mac_manufacturer_table
2747
 * NAME
2748
 *   load_mac_manufacturer_table
2749
 * INPUTS
2750
 *   none
2751
 * RESULT
2752
 *   returns associative array with MAC-Manufacturer pairs
2753
 ******/
2754
function load_mac_manufacturer_table() {
2755
	/* load MAC-Manufacture data from the file */
2756
	$macs = false;
2757
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2758
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2759
	}
2760
	if ($macs) {
2761
		foreach ($macs as $line) {
2762
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2763
				/* store values like this $mac_man['000C29']='VMware' */
2764
				$mac_man["$matches[1]"] = $matches[2];
2765
			}
2766
		}
2767
		return $mac_man;
2768
	} else {
2769
		return -1;
2770
	}
2771

    
2772
}
2773

    
2774
/****f* pfsense-utils/is_ipaddr_configured
2775
 * NAME
2776
 *   is_ipaddr_configured
2777
 * INPUTS
2778
 *   IP Address to check.
2779
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2780
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2781
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2782
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2783
 *     If check_subnets is true and cidrprefix is specified,
2784
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2785
 * RESULT
2786
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2787
*/
2788
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2789
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2790
		return true;
2791
	}
2792
	return false;
2793
}
2794

    
2795
/****f* pfsense-utils/where_is_ipaddr_configured
2796
 * NAME
2797
 *   where_is_ipaddr_configured
2798
 * INPUTS
2799
 *   IP Address to check.
2800
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2801
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2802
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2803
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2804
 *     If check_subnets is true and cidrprefix is specified,
2805
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2806
 * RESULT
2807
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2808
 *   If there are no matches then an empty array is returned.
2809
*/
2810
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2811
	global $config;
2812

    
2813
	$where_configured = array();
2814

    
2815
	$pos = strpos($ignore_if, '_virtualip');
2816
	if ($pos !== false) {
2817
		$ignore_vip_id = substr($ignore_if, $pos+10);
2818
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2819
	} else {
2820
		$ignore_vip_id = -1;
2821
		$ignore_vip_if = $ignore_if;
2822
	}
2823

    
2824
	$isipv6 = is_ipaddrv6($ipaddr);
2825

    
2826
	if ($isipv6) {
2827
		$ipaddr = text_to_compressed_ip6($ipaddr);
2828
	}
2829

    
2830
	if ($check_subnets) {
2831
		$cidrprefix = intval($cidrprefix);
2832
		if ($isipv6) {
2833
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2834
				$cidrprefix = 128;
2835
			}
2836
		} else {
2837
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2838
				$cidrprefix = 32;
2839
			}
2840
		}
2841
		$iflist = get_configured_interface_list();
2842
		foreach ($iflist as $if => $ifname) {
2843
			if ($ignore_if == $if) {
2844
				continue;
2845
			}
2846

    
2847
			if ($isipv6) {
2848
				$if_ipv6 = get_interface_ipv6($if);
2849
				$if_snbitsv6 = get_interface_subnetv6($if);
2850
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2851
					$where_entry = array();
2852
					$where_entry['if'] = $if;
2853
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2854
					$where_configured[] = $where_entry;
2855
				}
2856
			} else {
2857
				$if_ipv4 = get_interface_ip($if);
2858
				$if_snbitsv4 = get_interface_subnet($if);
2859
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
2860
					$where_entry = array();
2861
					$where_entry['if'] = $if;
2862
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
2863
					$where_configured[] = $where_entry;
2864
				}
2865
			}
2866
		}
2867
	} else {
2868
		if ($isipv6) {
2869
			$interface_list_ips = get_configured_ipv6_addresses();
2870
		} else {
2871
			$interface_list_ips = get_configured_ip_addresses();
2872
		}
2873

    
2874
		foreach ($interface_list_ips as $if => $ilips) {
2875
			if ($ignore_if == $if) {
2876
				continue;
2877
			}
2878
			if (strcasecmp($ipaddr, $ilips) == 0) {
2879
				$where_entry = array();
2880
				$where_entry['if'] = $if;
2881
				$where_entry['ip_or_subnet'] = $ilips;
2882
				$where_configured[] = $where_entry;
2883
			}
2884
		}
2885
	}
2886

    
2887
	if ($check_localip) {
2888
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, text_to_compressed_ip6($config['l2tp']['localip'])) == 0)) {
2889
			$where_entry = array();
2890
			$where_entry['if'] = 'l2tp';
2891
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
2892
			$where_configured[] = $where_entry;
2893
		}
2894
	}
2895

    
2896
	return $where_configured;
2897
}
2898

    
2899
/****f* pfsense-utils/pfSense_handle_custom_code
2900
 * NAME
2901
 *   pfSense_handle_custom_code
2902
 * INPUTS
2903
 *   directory name to process
2904
 * RESULT
2905
 *   globs the directory and includes the files
2906
 */
2907
function pfSense_handle_custom_code($src_dir) {
2908
	// Allow extending of the nat edit page and include custom input validation
2909
	if (is_dir("$src_dir")) {
2910
		$cf = glob($src_dir . "/*.inc");
2911
		foreach ($cf as $nf) {
2912
			if ($nf == "." || $nf == "..") {
2913
				continue;
2914
			}
2915
			// Include the extra handler
2916
			include_once("$nf");
2917
		}
2918
	}
2919
}
2920

    
2921
function set_language() {
2922
	global $config, $g;
2923

    
2924
	if (!empty($config['system']['language'])) {
2925
		$lang = $config['system']['language'];
2926
	} elseif (!empty($g['language'])) {
2927
		$lang = $g['language'];
2928
	}
2929
	$lang .= ".UTF-8";
2930

    
2931
	putenv("LANG={$lang}");
2932
	setlocale(LC_ALL, $lang);
2933
	textdomain("pfSense");
2934
	bindtextdomain("pfSense", "/usr/local/share/locale");
2935
	bind_textdomain_codeset("pfSense", $lang);
2936
}
2937

    
2938
function get_locale_list() {
2939
	$locales = array(
2940
		"bs" => gettext("Bosnian"),
2941
		"zh_Hans_CN" => gettext("Chinese (Simplified, China)"),
2942
		"zh_TW" => gettext("Chinese (Taiwan)"),
2943
		"nl" => gettext("Dutch"),
2944
		"en_US" => gettext("English"),
2945
		"de_DE" => gettext("German (Germany)"),
2946
		"nb" => gettext("Norwegian Bokmål"),
2947
		"pl" => gettext("Polish"),
2948
		"pt_BR" => gettext("Portuguese (Brazil)"),
2949
		"ru" => gettext("Russian"),
2950
		"es" => gettext("Spanish"),
2951
		"es_AR" => gettext("Spanish (Argentina)"),
2952
	);
2953

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

    
2958
	//asort($locales);
2959

    
2960
	return $locales;
2961
}
2962

    
2963
function return_hex_ipv4($ipv4) {
2964
	if (!is_ipaddrv4($ipv4)) {
2965
		return(false);
2966
	}
2967

    
2968
	/* we need the hex form of the interface IPv4 address */
2969
	$ip4arr = explode(".", $ipv4);
2970
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
2971
}
2972

    
2973
function convert_ipv6_to_128bit($ipv6) {
2974
	if (!is_ipaddrv6($ipv6)) {
2975
		return(false);
2976
	}
2977

    
2978
	$ip6arr = array();
2979
	$ip6prefix = Net_IPv6::uncompress($ipv6);
2980
	$ip6arr = explode(":", $ip6prefix);
2981
	/* binary presentation of the prefix for all 128 bits. */
2982
	$ip6prefixbin = "";
2983
	foreach ($ip6arr as $element) {
2984
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
2985
	}
2986
	return($ip6prefixbin);
2987
}
2988

    
2989
function convert_128bit_to_ipv6($ip6bin) {
2990
	if (strlen($ip6bin) <> 128) {
2991
		return(false);
2992
	}
2993

    
2994
	$ip6arr = array();
2995
	$ip6binarr = array();
2996
	$ip6binarr = str_split($ip6bin, 16);
2997
	foreach ($ip6binarr as $binpart) {
2998
		$ip6arr[] = dechex(bindec($binpart));
2999
	}
3000
	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
3001

    
3002
	return($ip6addr);
3003
}
3004

    
3005

    
3006
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3007
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3008
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3009
/* 6to4 is 16 bits, e.g. 65535 */
3010
function calculate_ipv6_delegation_length($if) {
3011
	global $config;
3012

    
3013
	if (!is_array($config['interfaces'][$if])) {
3014
		return false;
3015
	}
3016

    
3017
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3018
		case "6to4":
3019
			$pdlen = 16;
3020
			break;
3021
		case "6rd":
3022
			$rd6cfg = $config['interfaces'][$if];
3023
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3024
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
3025
			break;
3026
		case "dhcp6":
3027
			$dhcp6cfg = $config['interfaces'][$if];
3028
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3029
			break;
3030
		default:
3031
			$pdlen = 0;
3032
			break;
3033
	}
3034
	return($pdlen);
3035
}
3036

    
3037
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3038
	$prefix = Net_IPv6::uncompress($prefix, true);
3039
	$suffix = Net_IPv6::uncompress($suffix, true);
3040

    
3041
	/*
3042
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3043
	 *                ^^^^ ^
3044
	 *                |||| \-> 64
3045
	 *                |||\---> 63, 62, 61, 60
3046
	 *                ||\----> 56
3047
	 *                |\-----> 52
3048
	 *                \------> 48
3049
	 */
3050

    
3051
	switch ($len) {
3052
	case 48:
3053
		$prefix_len = 15;
3054
		break;
3055
	case 52:
3056
		$prefix_len = 16;
3057
		break;
3058
	case 56:
3059
		$prefix_len = 17;
3060
		break;
3061
	case 59:
3062
	case 60:
3063
		$prefix_len = 18;
3064
		break;
3065
	/*
3066
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
3067
	 * we let user chose this bit it can end up out of PD network
3068
	 *
3069
	 * Leave this with 20 for now until we find a way to let user
3070
	 * chose it. The side-effect is users with PD with one of these
3071
	 * lengths will not be able to setup DHCP server range for full
3072
	 * PD size, only for last /64 network
3073
	 */
3074
	case 63:
3075
	case 62:
3076
	case 61:
3077
	default:
3078
		$prefix_len = 20;
3079
		break;
3080
	}
3081

    
3082
	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
3083
	    substr($suffix, $prefix_len));
3084
}
3085

    
3086
function dhcpv6_pd_str_help($pdlen) {
3087
	$result = '';
3088

    
3089
	switch ($pdlen) {
3090
	case 48:
3091
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
3092
		break;
3093
	case 52:
3094
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
3095
		break;
3096
	case 56:
3097
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
3098
		break;
3099
	case 59:
3100
	case 60:
3101
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
3102
		break;
3103
	/*
3104
	 * XXX 63, 62 and 61 should use same mask as 60 but if
3105
	 * we let the user choose this bit it can end up out of PD network
3106
	 *
3107
	 * Leave this with the same as 64 for now until we find a way to
3108
	 * let the user choose it. The side-effect is users with PD with one
3109
	 * of these lengths will not be able to setup DHCP server ranges
3110
	 * for full PD size, only for last /64 network
3111
	 */
3112
	case 61:
3113
	case 62:
3114
	case 63:
3115
	case 64:
3116
	default:
3117
		$result = '::xxxx:xxxx:xxxx:xxxx';
3118
		break;
3119
	}
3120

    
3121
	return $result;
3122
}
3123

    
3124
function huawei_rssi_to_string($rssi) {
3125
	$dbm = array();
3126
	$i = 0;
3127
	$dbstart = -113;
3128
	while ($i < 32) {
3129
		$dbm[$i] = $dbstart + ($i * 2);
3130
		$i++;
3131
	}
3132
	$percent = round(($rssi / 31) * 100);
3133
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3134
	return $string;
3135
}
3136

    
3137
function huawei_mode_to_string($mode, $submode) {
3138
	$modes[0] = gettext("None");
3139
	$modes[1] = "AMPS";
3140
	$modes[2] = "CDMA";
3141
	$modes[3] = "GSM/GPRS";
3142
	$modes[4] = "HDR";
3143
	$modes[5] = "WCDMA";
3144
	$modes[6] = "GPS";
3145

    
3146
	$submodes[0] = gettext("No Service");
3147
	$submodes[1] = "GSM";
3148
	$submodes[2] = "GPRS";
3149
	$submodes[3] = "EDGE";
3150
	$submodes[4] = "WCDMA";
3151
	$submodes[5] = "HSDPA";
3152
	$submodes[6] = "HSUPA";
3153
	$submodes[7] = "HSDPA+HSUPA";
3154
	$submodes[8] = "TD-SCDMA";
3155
	$submodes[9] = "HSPA+";
3156
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3157
	return $string;
3158
}
3159

    
3160
function huawei_service_to_string($state) {
3161
	$modes[0] = gettext("No Service");
3162
	$modes[1] = gettext("Restricted Service");
3163
	$modes[2] = gettext("Valid Service");
3164
	$modes[3] = gettext("Restricted Regional Service");
3165
	$modes[4] = gettext("Powersaving Service");
3166
	$modes[255] = gettext("Unknown Service");
3167
	$string = $modes[$state];
3168
	return $string;
3169
}
3170

    
3171
function huawei_simstate_to_string($state) {
3172
	$modes[0] = gettext("Invalid SIM/locked State");
3173
	$modes[1] = gettext("Valid SIM State");
3174
	$modes[2] = gettext("Invalid SIM CS State");
3175
	$modes[3] = gettext("Invalid SIM PS State");
3176
	$modes[4] = gettext("Invalid SIM CS/PS State");
3177
	$modes[255] = gettext("Missing SIM State");
3178
	$string = $modes[$state];
3179
	return $string;
3180
}
3181

    
3182
function zte_rssi_to_string($rssi) {
3183
	return huawei_rssi_to_string($rssi);
3184
}
3185

    
3186
function zte_mode_to_string($mode, $submode) {
3187
	$modes[0] = gettext("No Service");
3188
	$modes[1] = gettext("Limited Service");
3189
	$modes[2] = "GPRS";
3190
	$modes[3] = "GSM";
3191
	$modes[4] = "UMTS";
3192
	$modes[5] = "EDGE";
3193
	$modes[6] = "HSDPA";
3194

    
3195
	$submodes[0] = "CS_ONLY";
3196
	$submodes[1] = "PS_ONLY";
3197
	$submodes[2] = "CS_PS";
3198
	$submodes[3] = "CAMPED";
3199
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3200
	return $string;
3201
}
3202

    
3203
function zte_service_to_string($service) {
3204
	$modes[0] = gettext("Initializing Service");
3205
	$modes[1] = gettext("Network Lock error Service");
3206
	$modes[2] = gettext("Network Locked Service");
3207
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3208
	$string = $modes[$service];
3209
	return $string;
3210
}
3211

    
3212
function zte_simstate_to_string($state) {
3213
	$modes[0] = gettext("No action State");
3214
	$modes[1] = gettext("Network lock State");
3215
	$modes[2] = gettext("(U)SIM card lock State");
3216
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3217
	$string = $modes[$state];
3218
	return $string;
3219
}
3220

    
3221
function get_configured_pppoe_server_interfaces() {
3222
	global $config;
3223
	$iflist = array();
3224
	if (is_array($config['pppoes']['pppoe'])) {
3225
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3226
			if ($pppoe['mode'] == "server") {
3227
				$int = "poes". $pppoe['pppoeid'];
3228
				$iflist[$int] = strtoupper($int);
3229
			}
3230
		}
3231
	}
3232
	return $iflist;
3233
}
3234

    
3235
function get_pppoes_child_interfaces($ifpattern) {
3236
	$if_arr = array();
3237
	if ($ifpattern == "") {
3238
		return;
3239
	}
3240

    
3241
	exec("/sbin/ifconfig", $out, $ret);
3242
	foreach ($out as $line) {
3243
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3244
			$if_arr[] = $match[1];
3245
		}
3246
	}
3247
	return $if_arr;
3248

    
3249
}
3250

    
3251
/****f* pfsense-utils/pkg_call_plugins
3252
 * NAME
3253
 *   pkg_call_plugins
3254
 * INPUTS
3255
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3256
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3257
 * RESULT
3258
 *   returns associative array results from the plugin calls for each package
3259
 * NOTES
3260
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3261
 ******/
3262
function pkg_call_plugins($plugin_type, $plugin_params) {
3263
	global $g, $config;
3264
	$results = array();
3265
	if (!is_array($config['installedpackages']['package'])) {
3266
		return $results;
3267
	}
3268
	foreach ($config['installedpackages']['package'] as $package) {
3269
		if (is_array($package['plugins']['item'])) {
3270
			foreach ($package['plugins']['item'] as $plugin) {
3271
				if ($plugin['type'] == $plugin_type) {
3272
					if (file_exists($package['include_file'])) {
3273
						require_once($package['include_file']);
3274
					} else {
3275
						continue;
3276
					}
3277
					$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3278
					$plugin_function = $pkgname . '_'. $plugin_type;
3279
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3280
				}
3281
			}
3282
		}
3283
	}
3284
	return $results;
3285
}
3286

    
3287
// Convert IPv6 addresses to lower case
3288
function addrtolower($ip) {
3289
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3290
		return(strtolower($ip));
3291
	} else {
3292
		return($ip);
3293
	}
3294
}
3295

    
3296
function compare_by_name($a, $b) {
3297
	return strcasecmp($a['name'], $b['name']);
3298
}
3299
?>
(32-32/54)