Project

General

Profile

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
217
	$csslist = get_css_files();
218

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
501
		$form->add($section);
502
	}
503
}
504

    
505
function hardware_offloading_applyflags($iface) {
506
	global $config;
507

    
508
	$flags_on = 0;
509
	$flags_off = 0;
510
	$options = pfSense_get_interface_addresses($iface);
511

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

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

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

    
552
	pfSense_interface_capabilities($iface, -$flags_off);
553
	pfSense_interface_capabilities($iface, $flags_on);
554
}
555

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
740
	return "";
741
}
742

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

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

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

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

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

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

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

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

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

    
829
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
830

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

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

    
852
	return false;
853
}
854

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1021
	/* parse config.xml again */
1022
	$config = parse_config(true);
1023

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

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

    
1034
	/* set up interfaces */
1035
	interfaces_configure();
1036
}
1037

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

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

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

    
1073
	/* parse config.xml again */
1074
	$config = parse_config(true);
1075

    
1076
	/* set up our timezone */
1077
	system_timezone_configure();
1078

    
1079
	/* set up our hostname */
1080
	system_hostname_configure();
1081

    
1082
	/* make hosts file */
1083
	system_hosts_generate();
1084

    
1085
	/* generate resolv.conf */
1086
	system_resolvconf_generate();
1087

    
1088
	/* enable routing */
1089
	system_routing_enable();
1090

    
1091
	/* set up interfaces */
1092
	interfaces_configure();
1093

    
1094
	/* start dyndns service */
1095
	services_dyndns_configure();
1096

    
1097
	/* configure cron service */
1098
	configure_cron();
1099

    
1100
	/* start the NTP client */
1101
	system_ntp_configure();
1102

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

    
1107
	/* restart sshd */
1108
	send_event("service restart sshd");
1109

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

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

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

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

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

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

    
1162
	unset($boot_config, $boot_config_file, $boot_config_split);
1163

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

    
1169
	if (file_exists($loader_conf_file)) {
1170
		$loader_conf = file_get_contents($loader_conf_file);
1171
	} elseif (file_exists("{$path}/boot/loader.conf.local")) {
1172
		$loader_conf_file = "{$path}/boot/loader.conf.local";
1173
		$loader_conf = file_get_contents($loader_conf_file);
1174
	} else {
1175
		$loader_conf = "";
1176
	}
1177
	$loader_conf_split = explode("\n", $loader_conf);
1178

    
1179
	$data = array();
1180
	// Loop through and only add lines that are not empty, and which
1181
	//  do not contain a console directive.
1182
	foreach ($loader_conf_split as $bcs) {
1183
		if (!empty($bcs) &&
1184
		    (stripos($bcs, "console") === false) &&
1185
		    (stripos($bcs, "boot_multicons") === false) &&
1186
		    (stripos($bcs, "boot_serial") === false) &&
1187
		    (stripos($bcs, "hw.usb.no_pf") === false) &&
1188
		    (stripos($bcs, "hint.uart.0.flags") === false) &&
1189
		    (stripos($bcs, "hint.uart.1.flags") === false)) {
1190
			$data[] = $bcs;
1191
		}
1192
	}
1193

    
1194
	if ($serial_only === true) {
1195
		$data[] = 'boot_serial="YES"';
1196
		$data[] = 'console="comconsole"';
1197
	} elseif ($vga_only === true) {
1198
		$data[] = 'console="vidconsole"';
1199
	} elseif (is_serial_enabled()) {
1200
		$data[] = 'boot_multicons="YES"';
1201
		$data[] = 'boot_serial="YES"';
1202
		$primaryconsole = isset($g['primaryconsole_force']) ?
1203
		    $g['primaryconsole_force'] :
1204
		    $config['system']['primaryconsole'];
1205
		switch ($primaryconsole) {
1206
			case "video":
1207
				$data[] = 'console="vidconsole,comconsole"';
1208
				break;
1209
			case "serial":
1210
			default:
1211
				$data[] = 'console="comconsole,vidconsole"';
1212
		}
1213
	}
1214
	$data[] = 'comconsole_speed="' . $serialspeed . '"';
1215

    
1216
	if ($specific_platform['name'] == 'RCC-VE' ||
1217
	    $specific_platform['name'] == 'RCC' ||
1218
	    $specific_platform['name'] == 'RCC-DFF') {
1219
		$data[] = 'comconsole_port="0x2F8"';
1220
		$data[] = 'hint.uart.0.flags="0x00"';
1221
		$data[] = 'hint.uart.1.flags="0x10"';
1222
	}
1223
	$data[] = 'hw.usb.no_pf="1"';
1224

    
1225
	safe_write_file($loader_conf_file, $data);
1226

    
1227
	unset($loader_conf, $loader_conf_split, $loader_config_file);
1228

    
1229
	$ttys = file_get_contents($ttys_file);
1230
	$ttys_split = explode("\n", $ttys);
1231

    
1232
	$data = array();
1233

    
1234
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1235

    
1236
	if (isset($config['system']['disableconsolemenu'])) {
1237
		$console_type = 'Pc';
1238
		$serial_type = '3wire';
1239
	} else {
1240
		$console_type = 'al.Pc';
1241
		$serial_type = 'al.3wire';
1242
	}
1243

    
1244
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1245
	$ttyv0_line =
1246
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\txterm\ton\tsecure";
1247
	$ttyu_line =
1248
	    "\"/usr/libexec/getty {$serial_type}\"\tvt100\t{$on_off}\tsecure";
1249

    
1250
	$found = array();
1251

    
1252
	foreach ($ttys_split as $tty) {
1253
		/* Ignore blank lines */
1254
		if (empty($tty)) {
1255
			continue;
1256
		}
1257

    
1258
		if (stristr($tty, "ttyv0")) {
1259
			$found['ttyv0'] = 1;
1260
			$data[] = $ttyv0_line;
1261
		} elseif (stristr($tty, "ttyu")) {
1262
			$ttyn = substr($tty, 0, 5);
1263
			$found[$ttyn] = 1;
1264
			$data[] = "{$ttyn}\t{$ttyu_line}";
1265
		} elseif (substr($tty, 0, 7) == 'console') {
1266
			$found['console'] = 1;
1267
			$data[] = $tty;
1268
		} else {
1269
			$data[] = $tty;
1270
		}
1271
	}
1272
	unset($on_off, $console_type, $serial_type);
1273

    
1274
	/* Detect missing main lines on original file and try to rebuild it */
1275
	$items = array(
1276
		'console',
1277
		'ttyv0',
1278
		'ttyu0',
1279
		'ttyu1',
1280
		'ttyu2',
1281
		'ttyu3'
1282
	);
1283

    
1284
	foreach ($items as $item) {
1285
		if (isset($found[$item])) {
1286
			continue;
1287
		}
1288

    
1289
		if ($item == 'console') {
1290
			$data[] = $console_line;
1291
		} elseif ($item == 'ttyv0') {
1292
			$data[] = $ttyv0_line;
1293
		} else {
1294
			$data[] = "{$item}\t{$ttyu_line}";
1295
		}
1296
	}
1297

    
1298
	safe_write_file($ttys_file, $data);
1299

    
1300
	unset($ttys, $ttys_file, $ttys_split, $data);
1301

    
1302
	if ($when != "upgrade") {
1303
		reload_ttys();
1304
	}
1305

    
1306
	return;
1307
}
1308

    
1309
function is_serial_enabled() {
1310
	global $g, $config;
1311

    
1312
	if (!isset($g['enableserial_force']) &&
1313
	    !isset($config['system']['enableserial'])) {
1314
		return false;
1315
	}
1316

    
1317
	return true;
1318
}
1319

    
1320
function reload_ttys() {
1321
	// Send a HUP signal to init will make it reload /etc/ttys
1322
	posix_kill(1, SIGHUP);
1323
}
1324

    
1325
function print_value_list($list, $count = 10, $separator = ",") {
1326
	$list = implode($separator, array_slice($list, 0, $count));
1327
	if (count($list) < $count) {
1328
		$list .= ".";
1329
	} else {
1330
		$list .= "...";
1331
	}
1332
	return $list;
1333
}
1334

    
1335
/* DHCP enabled on any interfaces? */
1336
function is_dhcp_server_enabled() {
1337
	global $config;
1338

    
1339
	if (!is_array($config['dhcpd'])) {
1340
		return false;
1341
	}
1342

    
1343
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1344
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1345
			return true;
1346
		}
1347
	}
1348

    
1349
	return false;
1350
}
1351

    
1352
/* DHCP enabled on any interfaces? */
1353
function is_dhcpv6_server_enabled() {
1354
	global $config;
1355

    
1356
	if (is_array($config['interfaces'])) {
1357
		foreach ($config['interfaces'] as $ifcfg) {
1358
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1359
				return true;
1360
			}
1361
		}
1362
	}
1363

    
1364
	if (!is_array($config['dhcpdv6'])) {
1365
		return false;
1366
	}
1367

    
1368
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1369
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1370
			return true;
1371
		}
1372
	}
1373

    
1374
	return false;
1375
}
1376

    
1377
/* radvd enabled on any interfaces? */
1378
function is_radvd_enabled() {
1379
	global $config;
1380

    
1381
	if (!is_array($config['dhcpdv6'])) {
1382
		$config['dhcpdv6'] = array();
1383
	}
1384

    
1385
	$dhcpdv6cfg = $config['dhcpdv6'];
1386
	$Iflist = get_configured_interface_list();
1387

    
1388
	/* handle manually configured DHCP6 server settings first */
1389
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1390
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1391
			continue;
1392
		}
1393

    
1394
		if (!isset($dhcpv6ifconf['ramode'])) {
1395
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1396
		}
1397

    
1398
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1399
			continue;
1400
		}
1401

    
1402
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1403
		if (!is_ipaddrv6($ifcfgipv6)) {
1404
			continue;
1405
		}
1406

    
1407
		return true;
1408
	}
1409

    
1410
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1411
	foreach ($Iflist as $if => $ifdescr) {
1412
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1413
			continue;
1414
		}
1415
		if (!isset($config['interfaces'][$if]['enable'])) {
1416
			continue;
1417
		}
1418

    
1419
		$ifcfgipv6 = get_interface_ipv6($if);
1420
		if (!is_ipaddrv6($ifcfgipv6)) {
1421
			continue;
1422
		}
1423

    
1424
		$ifcfgsnv6 = get_interface_subnetv6($if);
1425
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1426

    
1427
		if (!is_ipaddrv6($subnetv6)) {
1428
			continue;
1429
		}
1430

    
1431
		return true;
1432
	}
1433

    
1434
	return false;
1435
}
1436

    
1437
/* Any PPPoE servers enabled? */
1438
function is_pppoe_server_enabled() {
1439
	global $config;
1440

    
1441
	$pppoeenable = false;
1442

    
1443
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1444
		return false;
1445
	}
1446

    
1447
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1448
		if ($pppoes['mode'] == 'server') {
1449
			$pppoeenable = true;
1450
		}
1451
	}
1452

    
1453
	return $pppoeenable;
1454
}
1455

    
1456
/* Optional arg forces hh:mm:ss without days */
1457
function convert_seconds_to_dhms($sec, $showhoursonly = false) {
1458
	if (!is_numericint($sec)) {
1459
		return '-';
1460
	}
1461
	// FIXME: When we move to PHP 7 we can use "intdiv($sec % X, Y)" etc
1462
	list($d, $h, $m, $s) = array(	(int)($showhoursonly ? 0 : $sec/86400),
1463
					(int)(($showhoursonly ? $sec : $sec % 86400)/3600),
1464
					(int)(($sec % 3600)/60),
1465
					$sec % 60
1466
				);
1467
	return ($d > 0 ? $d . 'd ' : '') . sprintf('%02d:%02d:%02d', $h, $m, $s);
1468
}
1469

    
1470
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1471

    
1472
function get_ppp_uptime($port) {
1473
	if (file_exists("/conf/{$port}.log")) {
1474
		$saved_time = file_get_contents("/conf/{$port}.log");
1475
		$uptime_data = explode("\n", $saved_time);
1476
		$sec = 0;
1477
		foreach ($uptime_data as $upt) {
1478
			$sec += substr($upt, 1 + strpos($upt, " "));
1479
		}
1480
		return convert_seconds_to_dhms($sec);
1481
	} else {
1482
		$total_time = gettext("No history data found!");
1483
		return $total_time;
1484
	}
1485
}
1486

    
1487
//returns interface information
1488
function get_interface_info($ifdescr) {
1489
	global $config, $g;
1490

    
1491
	$ifinfo = array();
1492
	if (empty($config['interfaces'][$ifdescr])) {
1493
		return;
1494
	}
1495
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1496
	$ifinfo['enable'] = isset($config['interfaces'][$ifdescr]['enable']);
1497
	$ifinfo['if'] = get_real_interface($ifdescr);
1498

    
1499
	$chkif = $ifinfo['if'];
1500
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1501
	$ifinfo['status'] = $ifinfotmp['status'];
1502
	if (empty($ifinfo['status'])) {
1503
		$ifinfo['status'] = "down";
1504
	}
1505
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1506
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1507
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1508
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1509
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1510
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1511
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1512
	if (isset($ifinfotmp['link0'])) {
1513
		$link0 = "down";
1514
	}
1515
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1516
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1517
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1518
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1519
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1520
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1521

    
1522
	/* Use pfctl for non wrapping 64 bit counters */
1523
	/* Pass */
1524
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1525
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1526
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1527
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1528
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1529
	$in4_pass = $pf_in4_pass[5];
1530
	$out4_pass = $pf_out4_pass[5];
1531
	$in4_pass_packets = $pf_in4_pass[3];
1532
	$out4_pass_packets = $pf_out4_pass[3];
1533
	$in6_pass = $pf_in6_pass[5];
1534
	$out6_pass = $pf_out6_pass[5];
1535
	$in6_pass_packets = $pf_in6_pass[3];
1536
	$out6_pass_packets = $pf_out6_pass[3];
1537
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1538
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1539
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1540
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1541

    
1542
	/* Block */
1543
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1544
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1545
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1546
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1547
	$in4_block = $pf_in4_block[5];
1548
	$out4_block = $pf_out4_block[5];
1549
	$in4_block_packets = $pf_in4_block[3];
1550
	$out4_block_packets = $pf_out4_block[3];
1551
	$in6_block = $pf_in6_block[5];
1552
	$out6_block = $pf_out6_block[5];
1553
	$in6_block_packets = $pf_in6_block[3];
1554
	$out6_block_packets = $pf_out6_block[3];
1555
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1556
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1557
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1558
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1559

    
1560
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1561
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1562
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1563
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1564

    
1565
	$ifconfiginfo = "";
1566
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1567
	switch ($link_type) {
1568
		/* DHCP? -> see if dhclient is up */
1569
		case "dhcp":
1570
			/* see if dhclient is up */
1571
			if (find_dhclient_process($ifinfo['if']) != 0) {
1572
				$ifinfo['dhcplink'] = "up";
1573
			} else {
1574
				$ifinfo['dhcplink'] = "down";
1575
			}
1576

    
1577
			break;
1578
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1579
		case "pppoe":
1580
		case "pptp":
1581
		case "l2tp":
1582
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1583
				/* get PPPoE link status for dial on demand */
1584
				$ifinfo["{$link_type}link"] = "up";
1585
			} else {
1586
				$ifinfo["{$link_type}link"] = "down";
1587
			}
1588

    
1589
			break;
1590
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1591
		case "ppp":
1592
			if ($ifinfo['status'] == "up") {
1593
				$ifinfo['ppplink'] = "up";
1594
			} else {
1595
				$ifinfo['ppplink'] = "down" ;
1596
			}
1597

    
1598
			if (empty($ifinfo['status'])) {
1599
				$ifinfo['status'] = "down";
1600
			}
1601

    
1602
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1603
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1604
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1605
						break;
1606
					}
1607
				}
1608
			}
1609
			$dev = $ppp['ports'];
1610
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1611
				break;
1612
			}
1613
			if (!file_exists($dev)) {
1614
				$ifinfo['nodevice'] = 1;
1615
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1616
			}
1617

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

    
1653
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1654
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1655
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1656
	}
1657

    
1658
	if ($ifinfo['status'] == "up") {
1659
		/* try to determine media with ifconfig */
1660
		unset($ifconfiginfo);
1661
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1662
		$wifconfiginfo = array();
1663
		if (is_interface_wireless($ifdescr)) {
1664
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1665
			array_shift($wifconfiginfo);
1666
		}
1667
		$matches = "";
1668
		foreach ($ifconfiginfo as $ici) {
1669

    
1670
			/* don't list media/speed for wireless cards, as it always
1671
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1672
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1673
				$ifinfo['media'] = $matches[1];
1674
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1675
				$ifinfo['media'] = $matches[1];
1676
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1677
				$ifinfo['media'] = $matches[1];
1678
			}
1679

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

    
1725
	$bridge = "";
1726
	$bridge = link_interface_to_bridge($ifdescr);
1727
	if ($bridge) {
1728
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1729
		if (stristr($bridge_text, "blocking") <> false) {
1730
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1731
			$ifinfo['bridgeint'] = $bridge;
1732
		} else if (stristr($bridge_text, "learning") <> false) {
1733
			$ifinfo['bridge'] = gettext("learning");
1734
			$ifinfo['bridgeint'] = $bridge;
1735
		} else if (stristr($bridge_text, "forwarding") <> false) {
1736
			$ifinfo['bridge'] = gettext("forwarding");
1737
			$ifinfo['bridgeint'] = $bridge;
1738
		}
1739
	}
1740

    
1741
	return $ifinfo;
1742
}
1743

    
1744
//returns cpu speed of processor. Good for determining capabilities of machine
1745
function get_cpu_speed() {
1746
	return get_single_sysctl("hw.clockrate");
1747
}
1748

    
1749
function get_uptime_sec() {
1750
	$boottime = "";
1751
	$matches = "";
1752
	$boottime = get_single_sysctl("kern.boottime");
1753
	preg_match("/sec = (\d+)/", $boottime, $matches);
1754
	$boottime = $matches[1];
1755
	if (intval($boottime) == 0) {
1756
		return 0;
1757
	}
1758

    
1759
	$uptime = time() - $boottime;
1760
	return $uptime;
1761
}
1762

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

    
1796
function is_fqdn($fqdn) {
1797
	$hostname = false;
1798
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1799
		$hostname = true;
1800
	}
1801
	if (preg_match("/\.\./", $fqdn)) {
1802
		$hostname = false;
1803
	}
1804
	if (preg_match("/^\./i", $fqdn)) {
1805
		$hostname = false;
1806
	}
1807
	if (preg_match("/\//i", $fqdn)) {
1808
		$hostname = false;
1809
	}
1810
	return($hostname);
1811
}
1812

    
1813
function pfsense_default_state_size() {
1814
	/* get system memory amount */
1815
	$memory = get_memory();
1816
	$physmem = $memory[0];
1817
	/* Be cautious and only allocate 10% of system memory to the state table */
1818
	$max_states = (int) ($physmem/10)*1000;
1819
	return $max_states;
1820
}
1821

    
1822
function pfsense_default_tables_size() {
1823
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1824
	return $current;
1825
}
1826

    
1827
function pfsense_default_table_entries_size() {
1828
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1829
	return (trim($current));
1830
}
1831

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

    
1868
	if (trim($oldcontents) != trim($contents)) {
1869
		if ($g['debug']) {
1870
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1871
		}
1872
		return ($oldcontents);
1873
	} else {
1874
		return false;
1875
	}
1876
}
1877

    
1878
/*
1879
 * load_crypto() - Load crypto modules if enabled in config.
1880
 */
1881
function load_crypto() {
1882
	global $config, $g;
1883
	$crypto_modules = array('aesni', 'cryptodev');
1884

    
1885
	$enabled_modules = explode('_', $config['system']['crypto_hardware']);
1886

    
1887
	foreach ($enabled_modules as $enmod) {
1888
		if (empty($enmod) || !in_array($enmod, $crypto_modules)) {
1889
			continue;
1890
		}
1891
		if (!is_module_loaded($enmod)) {
1892
			log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $enmod));
1893
			mwexec("/sbin/kldload " . escapeshellarg($enmod));
1894
		}
1895
	}
1896
}
1897

    
1898
/*
1899
 * load_thermal_hardware() - Load temperature monitor kernel module
1900
 */
1901
function load_thermal_hardware() {
1902
	global $config, $g;
1903
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1904

    
1905
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1906
		return false;
1907
	}
1908

    
1909
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1910
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1911
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1912
	}
1913
}
1914

    
1915
/****f* pfsense-utils/isvm
1916
 * NAME
1917
 *   isvm
1918
 * INPUTS
1919
 *	none
1920
 * RESULT
1921
 *   returns true if machine is running under a virtual environment
1922
 ******/
1923
function isvm() {
1924
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
1925
	$_gb = exec('/bin/kenv -q smbios.system.product 2>/dev/null', $output, $rc);
1926

    
1927
	if ($rc != 0 || !isset($output[0])) {
1928
		return false;
1929
	}
1930

    
1931
	foreach ($virtualenvs as $virtualenv) {
1932
		if (stripos($output[0], $virtualenv) !== false) {
1933
			return true;
1934
		}
1935
	}
1936

    
1937
	return false;
1938
}
1939

    
1940
function get_freebsd_version() {
1941
	$version = explode(".", php_uname("r"));
1942
	return $version[0];
1943
}
1944

    
1945
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
1946
	global $config, $g;
1947

    
1948
	$fp = fopen($destination, "wb");
1949

    
1950
	if (!$fp) {
1951
		return false;
1952
	}
1953

    
1954
	$ch = curl_init();
1955
	curl_setopt($ch, CURLOPT_URL, $url);
1956
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
1957
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1958
	curl_setopt($ch, CURLOPT_FILE, $fp);
1959
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1960
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1961
	curl_setopt($ch, CURLOPT_HEADER, false);
1962
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1963
	if (!isset($config['system']['do_not_send_uniqueid'])) {
1964
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
1965
	} else {
1966
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
1967
	}
1968

    
1969
	if (!empty($config['system']['proxyurl'])) {
1970
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
1971
		if (!empty($config['system']['proxyport'])) {
1972
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
1973
		}
1974
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
1975
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
1976
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
1977
		}
1978
	}
1979

    
1980
	@curl_exec($ch);
1981
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
1982
	fclose($fp);
1983
	curl_close($ch);
1984
	if ($http_code == 200) {
1985
		return true;
1986
	} else {
1987
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
1988
		unlink_if_exists($destination);
1989
		return false;
1990
	}
1991
}
1992

    
1993
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
1994
	global $config, $g;
1995
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
1996
	$file_size = 1;
1997
	$downloaded = 1;
1998
	$first_progress_update = TRUE;
1999
	/* open destination file */
2000
	$fout = fopen($destination, "wb");
2001

    
2002
	if (!$fout) {
2003
		return false;
2004
	}
2005
	/*
2006
	 *      Originally by Author: Keyvan Minoukadeh
2007
	 *      Modified by Scott Ullrich to return Content-Length size
2008
	 */
2009
	$ch = curl_init();
2010
	curl_setopt($ch, CURLOPT_URL, $url);
2011
	curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, $verify_ssl);
2012
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2013
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
2014
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2015
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
2016
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
2017
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2018
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2019
	if (!isset($config['system']['do_not_send_uniqueid'])) {
2020
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
2021
	} else {
2022
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2023
	}
2024

    
2025
	if (!empty($config['system']['proxyurl'])) {
2026
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2027
		if (!empty($config['system']['proxyport'])) {
2028
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2029
		}
2030
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2031
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2032
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2033
		}
2034
	}
2035

    
2036
	@curl_exec($ch);
2037
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2038
	fclose($fout);
2039
	curl_close($ch);
2040
	if ($http_code == 200) {
2041
		return true;
2042
	} else {
2043
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2044
		unlink_if_exists($destination);
2045
		return false;
2046
	}
2047
}
2048

    
2049
function read_header($ch, $string) {
2050
	global $file_size, $fout;
2051
	$length = strlen($string);
2052
	$regs = "";
2053
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
2054
	if ($regs[2] <> "") {
2055
		$file_size = intval($regs[2]);
2056
	}
2057
	ob_flush();
2058
	return $length;
2059
}
2060

    
2061
function read_body($ch, $string) {
2062
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
2063
	global $pkg_interface;
2064
	$length = strlen($string);
2065
	$downloaded += intval($length);
2066
	if ($file_size > 0) {
2067
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
2068
		$downloadProgress = 100 - $downloadProgress;
2069
	} else {
2070
		$downloadProgress = 0;
2071
	}
2072
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
2073
		if ($sendto == "status") {
2074
			if ($pkg_interface == "console") {
2075
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2076
					$tostatus = $static_status . $downloadProgress . "%";
2077
					if ($downloadProgress == 100) {
2078
						$tostatus = $tostatus . "\r";
2079
					}
2080
					update_status($tostatus);
2081
				}
2082
			} else {
2083
				$tostatus = $static_status . $downloadProgress . "%";
2084
				update_status($tostatus);
2085
			}
2086
		} else {
2087
			if ($pkg_interface == "console") {
2088
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2089
					$tooutput = $static_output . $downloadProgress . "%";
2090
					if ($downloadProgress == 100) {
2091
						$tooutput = $tooutput . "\r";
2092
					}
2093
					update_output_window($tooutput);
2094
				}
2095
			} else {
2096
				$tooutput = $static_output . $downloadProgress . "%";
2097
				update_output_window($tooutput);
2098
			}
2099
		}
2100
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
2101
			update_progress_bar($downloadProgress, $first_progress_update);
2102
			$first_progress_update = FALSE;
2103
		}
2104
		$lastseen = $downloadProgress;
2105
	}
2106
	if ($fout) {
2107
		fwrite($fout, $string);
2108
	}
2109
	ob_flush();
2110
	return $length;
2111
}
2112

    
2113
/*
2114
 *   update_output_window: update bottom textarea dynamically.
2115
 */
2116
function update_output_window($text) {
2117
	global $pkg_interface;
2118
	$log = preg_replace("/\n/", "\\n", $text);
2119
	if ($pkg_interface != "console") {
2120
?>
2121
<script type="text/javascript">
2122
//<![CDATA[
2123
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
2124
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
2125
//]]>
2126
</script>
2127
<?php
2128
	}
2129
	/* ensure that contents are written out */
2130
	ob_flush();
2131
}
2132

    
2133
/*
2134
 *   update_status: update top textarea dynamically.
2135
 */
2136
function update_status($status) {
2137
	global $pkg_interface;
2138

    
2139
	if ($pkg_interface == "console") {
2140
		print ("{$status}");
2141
	}
2142

    
2143
	/* ensure that contents are written out */
2144
	ob_flush();
2145
}
2146

    
2147
/*
2148
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
2149
 */
2150
function update_progress_bar($percent, $first_time) {
2151
	global $pkg_interface;
2152
	if ($percent > 100) {
2153
		$percent = 1;
2154
	}
2155
	if ($pkg_interface <> "console") {
2156
		echo '<script type="text/javascript">';
2157
		echo "\n//<![CDATA[\n";
2158
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
2159
		echo "\n//]]>\n";
2160
		echo '</script>';
2161
	} else {
2162
		if (!($first_time)) {
2163
			echo "\x08\x08\x08\x08\x08";
2164
		}
2165
		echo sprintf("%4d%%", $percent);
2166
	}
2167
}
2168

    
2169
function update_alias_name($new_alias_name, $orig_alias_name) {
2170
	if (!$orig_alias_name) {
2171
		return;
2172
	}
2173

    
2174
	// Firewall rules
2175
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2176
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2177
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2178
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2179
	// NAT Rules
2180
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2181
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2182
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2183
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2184
	update_alias_names_upon_change(array('nat', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2185
	update_alias_names_upon_change(array('nat', 'rule'), array('local-port'), $new_alias_name, $orig_alias_name);
2186
	// NAT 1:1 Rules
2187
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('external'), $new_alias_name, $orig_alias_name);
2188
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2189
	update_alias_names_upon_change(array('nat', 'onetoone'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2190
	// NAT Outbound Rules
2191
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('source', 'network'), $new_alias_name, $orig_alias_name);
2192
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('sourceport'), $new_alias_name, $orig_alias_name);
2193
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2194
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('dstport'), $new_alias_name, $orig_alias_name);
2195
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2196
	// Alias in an alias
2197
	update_alias_names_upon_change(array('aliases', 'alias'), array('address'), $new_alias_name, $orig_alias_name);
2198
}
2199

    
2200
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2201
	global $g, $config, $pconfig, $debug;
2202
	if (!$origname) {
2203
		return;
2204
	}
2205

    
2206
	$sectionref = &$config;
2207
	foreach ($section as $sectionname) {
2208
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2209
			$sectionref = &$sectionref[$sectionname];
2210
		} else {
2211
			return;
2212
		}
2213
	}
2214

    
2215
	if ($debug) {
2216
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2217
		fwrite($fd, print_r($pconfig, true));
2218
	}
2219

    
2220
	if (is_array($sectionref)) {
2221
		foreach ($sectionref as $itemkey => $item) {
2222
			if ($debug) {
2223
				fwrite($fd, "$itemkey\n");
2224
			}
2225

    
2226
			$fieldfound = true;
2227
			$fieldref = &$sectionref[$itemkey];
2228
			foreach ($field as $fieldname) {
2229
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2230
					$fieldref = &$fieldref[$fieldname];
2231
				} else {
2232
					$fieldfound = false;
2233
					break;
2234
				}
2235
			}
2236
			if ($fieldfound && $fieldref == $origname) {
2237
				if ($debug) {
2238
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2239
				}
2240
				$fieldref = $new_alias_name;
2241
			}
2242
		}
2243
	}
2244

    
2245
	if ($debug) {
2246
		fclose($fd);
2247
	}
2248

    
2249
}
2250

    
2251
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2252
	/*
2253
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2254
	 * $type = if set to 'url' then subnets and ips will be returned,
2255
	 *         if set to 'url_ports' port-ranges and ports will be returned
2256
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2257
	 *
2258
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2259
	 */
2260

    
2261
	if (!file_exists($filename)) {
2262
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2263
		return null;
2264
	}
2265

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

    
2308
function update_alias_url_data() {
2309
	global $config, $g;
2310

    
2311
	$updated = false;
2312

    
2313
	/* item is a url type */
2314
	$lockkey = lock('aliasurl');
2315
	if (is_array($config['aliases']['alias'])) {
2316
		foreach ($config['aliases']['alias'] as $x => $alias) {
2317
			if (empty($alias['aliasurl'])) {
2318
				continue;
2319
			}
2320

    
2321
			$address = null;
2322
			foreach ($alias['aliasurl'] as $alias_url) {
2323
				/* fetch down and add in */
2324
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2325
				unlink($temp_filename);
2326
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2327
				mkdir($temp_filename);
2328
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2329
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2330
					continue;
2331
				}
2332

    
2333
				/* if the item is tar gzipped then extract */
2334
				if (stripos($alias_url, '.tgz')) {
2335
					if (!process_alias_tgz($temp_filename)) {
2336
						continue;
2337
					}
2338
				}
2339
				if (file_exists("{$temp_filename}/aliases")) {
2340
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2341
					mwexec("/bin/rm -rf {$temp_filename}");
2342
				}
2343
			}
2344
			if ($address != null) {
2345
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2346
				$updated = true;
2347
			}
2348
		}
2349
	}
2350
	unlock($lockkey);
2351

    
2352
	/* Report status to callers as well */
2353
	return $updated;
2354
}
2355

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

    
2386
	return true;
2387
}
2388

    
2389
function version_compare_dates($a, $b) {
2390
	$a_time = strtotime($a);
2391
	$b_time = strtotime($b);
2392

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

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

    
2477
		// First try to compare the numeric parts of the version string.
2478
		$v = version_compare_numeric($cur_num, $rem_num);
2479

    
2480
		// If the numeric parts are the same, compare the string parts.
2481
		if ($v == 0) {
2482
			return version_compare_string($cur_str, $rem_str);
2483
		}
2484
	}
2485
	return $v;
2486
}
2487
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2488
	global $g, $config;
2489

    
2490
	$urltable_prefix = "/var/db/aliastables/";
2491
	$urltable_filename = $urltable_prefix . $name . ".txt";
2492
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2493

    
2494
	// Make the aliases directory if it doesn't exist
2495
	if (!file_exists($urltable_prefix)) {
2496
		mkdir($urltable_prefix);
2497
	} elseif (!is_dir($urltable_prefix)) {
2498
		unlink($urltable_prefix);
2499
		mkdir($urltable_prefix);
2500
	}
2501

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

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

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

    
2516
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2517
			if ($type == "urltable_ports") {
2518
				$parsed_contents = group_ports($parsed_contents, true);
2519
			}
2520
			if (is_array($parsed_contents)) {
2521
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2522
			} else {
2523
				touch($urltable_filename);
2524
			}
2525

    
2526
			/* Remove existing archive and create an up to date archive if RAM disk is enabled. */
2527
			unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz");
2528
			if (isset($config['system']['use_mfs_tmpvar'])) {
2529
				mwexec("/usr/bin/tar -czf " . escapeshellarg("{$g['cf_conf_path']}/RAM_Disk_Store/{$name}.txt.tgz") . " -C / " . escapeshellarg($urltable_filename));
2530
			}
2531

    
2532
			unlink_if_exists($tmp_urltable_filename);
2533
		} else {
2534
			if (!$validateonly) {
2535
				touch($urltable_filename);
2536
			}
2537
			return false;
2538
		}
2539
		return true;
2540
	} else {
2541
		// File exists, and it doesn't need to be updated.
2542
		return -1;
2543
	}
2544
}
2545

    
2546
function get_include_contents($filename) {
2547
	if (is_file($filename)) {
2548
		ob_start();
2549
		include $filename;
2550
		$contents = ob_get_contents();
2551
		ob_end_clean();
2552
		return $contents;
2553
	}
2554
	return false;
2555
}
2556

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

    
2669
function get_country_name($country_code) {
2670
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2671
		return "";
2672
	}
2673

    
2674
	$country_names_xml = "/usr/local/share/pfSense/iso_3166-1_list_en.xml";
2675
	$country_names_contents = file_get_contents($country_names_xml);
2676
	$country_names = xml2array($country_names_contents);
2677

    
2678
	if ($country_code == "ALL") {
2679
		$country_list = array();
2680
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2681
			$country_list[] = array(
2682
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2683
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2684
		}
2685
		return $country_list;
2686
	}
2687

    
2688
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2689
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2690
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2691
		}
2692
	}
2693
	return "";
2694
}
2695

    
2696
/* sort by interface only, retain the original order of rules that apply to
2697
   the same interface */
2698
function filter_rules_sort() {
2699
	global $config;
2700

    
2701
	/* mark each rule with the sequence number (to retain the order while sorting) */
2702
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2703
		$config['filter']['rule'][$i]['seq'] = $i;
2704
	}
2705

    
2706
	usort($config['filter']['rule'], "filter_rules_compare");
2707

    
2708
	/* strip the sequence numbers again */
2709
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2710
		unset($config['filter']['rule'][$i]['seq']);
2711
	}
2712
}
2713
function filter_rules_compare($a, $b) {
2714
	if (isset($a['floating']) && isset($b['floating'])) {
2715
		return $a['seq'] - $b['seq'];
2716
	} else if (isset($a['floating'])) {
2717
		return -1;
2718
	} else if (isset($b['floating'])) {
2719
		return 1;
2720
	} else if ($a['interface'] == $b['interface']) {
2721
		return $a['seq'] - $b['seq'];
2722
	} else {
2723
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2724
	}
2725
}
2726

    
2727
function generate_ipv6_from_mac($mac) {
2728
	$elements = explode(":", $mac);
2729
	if (count($elements) <> 6) {
2730
		return false;
2731
	}
2732

    
2733
	$i = 0;
2734
	$ipv6 = "fe80::";
2735
	foreach ($elements as $byte) {
2736
		if ($i == 0) {
2737
			$hexadecimal = substr($byte, 1, 2);
2738
			$bitmap = base_convert($hexadecimal, 16, 2);
2739
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2740
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2741
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2742
		}
2743
		$ipv6 .= $byte;
2744
		if ($i == 1) {
2745
			$ipv6 .= ":";
2746
		}
2747
		if ($i == 3) {
2748
			$ipv6 .= ":";
2749
		}
2750
		if ($i == 2) {
2751
			$ipv6 .= "ff:fe";
2752
		}
2753

    
2754
		$i++;
2755
	}
2756
	return $ipv6;
2757
}
2758

    
2759
/****f* pfsense-utils/load_mac_manufacturer_table
2760
 * NAME
2761
 *   load_mac_manufacturer_table
2762
 * INPUTS
2763
 *   none
2764
 * RESULT
2765
 *   returns associative array with MAC-Manufacturer pairs
2766
 ******/
2767
function load_mac_manufacturer_table() {
2768
	/* load MAC-Manufacture data from the file */
2769
	$macs = false;
2770
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2771
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2772
	}
2773
	if ($macs) {
2774
		foreach ($macs as $line) {
2775
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2776
				/* store values like this $mac_man['000C29']='VMware' */
2777
				$mac_man["$matches[1]"] = $matches[2];
2778
			}
2779
		}
2780
		return $mac_man;
2781
	} else {
2782
		return -1;
2783
	}
2784

    
2785
}
2786

    
2787
/****f* pfsense-utils/is_ipaddr_configured
2788
 * NAME
2789
 *   is_ipaddr_configured
2790
 * INPUTS
2791
 *   IP Address to check.
2792
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2793
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2794
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2795
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2796
 *     If check_subnets is true and cidrprefix is specified,
2797
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2798
 * RESULT
2799
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
2800
*/
2801
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2802
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
2803
		return true;
2804
	}
2805
	return false;
2806
}
2807

    
2808
/****f* pfsense-utils/where_is_ipaddr_configured
2809
 * NAME
2810
 *   where_is_ipaddr_configured
2811
 * INPUTS
2812
 *   IP Address to check.
2813
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
2814
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
2815
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
2816
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
2817
 *     If check_subnets is true and cidrprefix is specified,
2818
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
2819
 * RESULT
2820
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
2821
 *   If there are no matches then an empty array is returned.
2822
*/
2823
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
2824
	global $config;
2825

    
2826
	$where_configured = array();
2827

    
2828
	$pos = strpos($ignore_if, '_virtualip');
2829
	if ($pos !== false) {
2830
		$ignore_vip_id = substr($ignore_if, $pos+10);
2831
		$ignore_vip_if = substr($ignore_if, 0, $pos);
2832
	} else {
2833
		$ignore_vip_id = -1;
2834
		$ignore_vip_if = $ignore_if;
2835
	}
2836

    
2837
	$isipv6 = is_ipaddrv6($ipaddr);
2838

    
2839
	if ($isipv6) {
2840
		$ipaddr = text_to_compressed_ip6($ipaddr);
2841
	}
2842

    
2843
	if ($check_subnets) {
2844
		$cidrprefix = intval($cidrprefix);
2845
		if ($isipv6) {
2846
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
2847
				$cidrprefix = 128;
2848
			}
2849
		} else {
2850
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
2851
				$cidrprefix = 32;
2852
			}
2853
		}
2854
		$iflist = get_configured_interface_list();
2855
		foreach ($iflist as $if => $ifname) {
2856
			if ($ignore_if == $if) {
2857
				continue;
2858
			}
2859

    
2860
			if ($isipv6) {
2861
				$if_ipv6 = get_interface_ipv6($if);
2862
				$if_snbitsv6 = get_interface_subnetv6($if);
2863
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
2864
					$where_entry = array();
2865
					$where_entry['if'] = $if;
2866
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
2867
					$where_configured[] = $where_entry;
2868
				}
2869
			} else {
2870
				$if_ipv4 = get_interface_ip($if);
2871
				$if_snbitsv4 = get_interface_subnet($if);
2872
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
2873
					$where_entry = array();
2874
					$where_entry['if'] = $if;
2875
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
2876
					$where_configured[] = $where_entry;
2877
				}
2878
			}
2879
		}
2880
	} else {
2881
		if ($isipv6) {
2882
			$interface_list_ips = get_configured_ipv6_addresses();
2883
		} else {
2884
			$interface_list_ips = get_configured_ip_addresses();
2885
		}
2886

    
2887
		foreach ($interface_list_ips as $if => $ilips) {
2888
			if ($ignore_if == $if) {
2889
				continue;
2890
			}
2891
			if (strcasecmp($ipaddr, $ilips) == 0) {
2892
				$where_entry = array();
2893
				$where_entry['if'] = $if;
2894
				$where_entry['ip_or_subnet'] = $ilips;
2895
				$where_configured[] = $where_entry;
2896
			}
2897
		}
2898
	}
2899

    
2900
	if ($check_localip) {
2901
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, text_to_compressed_ip6($config['l2tp']['localip'])) == 0)) {
2902
			$where_entry = array();
2903
			$where_entry['if'] = 'l2tp';
2904
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
2905
			$where_configured[] = $where_entry;
2906
		}
2907
	}
2908

    
2909
	return $where_configured;
2910
}
2911

    
2912
/****f* pfsense-utils/pfSense_handle_custom_code
2913
 * NAME
2914
 *   pfSense_handle_custom_code
2915
 * INPUTS
2916
 *   directory name to process
2917
 * RESULT
2918
 *   globs the directory and includes the files
2919
 */
2920
function pfSense_handle_custom_code($src_dir) {
2921
	// Allow extending of the nat edit page and include custom input validation
2922
	if (is_dir("$src_dir")) {
2923
		$cf = glob($src_dir . "/*.inc");
2924
		foreach ($cf as $nf) {
2925
			if ($nf == "." || $nf == "..") {
2926
				continue;
2927
			}
2928
			// Include the extra handler
2929
			include_once("$nf");
2930
		}
2931
	}
2932
}
2933

    
2934
function set_language() {
2935
	global $config, $g;
2936

    
2937
	if (!empty($config['system']['language'])) {
2938
		$lang = $config['system']['language'];
2939
	} elseif (!empty($g['language'])) {
2940
		$lang = $g['language'];
2941
	}
2942
	$lang .= ".UTF-8";
2943

    
2944
	putenv("LANG={$lang}");
2945
	setlocale(LC_ALL, $lang);
2946
	textdomain("pfSense");
2947
	bindtextdomain("pfSense", "/usr/local/share/locale");
2948
	bind_textdomain_codeset("pfSense", $lang);
2949
}
2950

    
2951
function get_locale_list() {
2952
	$locales = array(
2953
		"bs" => gettext("Bosnian"),
2954
		"zh_CN" => gettext("Chinese"),
2955
		"zh_Hans_CN" => gettext("Chinese (Simplified, China)"),
2956
		"zh_HK" => gettext("Chinese (Hong Kong)"),
2957
		"zh_TW" => gettext("Chinese (Taiwan)"),
2958
		"nl" => gettext("Dutch"),
2959
		"en_US" => gettext("English"),
2960
		"fr" => gettext("French"),
2961
		"de_DE" => gettext("German (Germany)"),
2962
		"nb" => gettext("Norwegian Bokmål"),
2963
		"pl" => gettext("Polish"),
2964
		"pt_PT" => gettext("Portuguese"),
2965
		"pt_BR" => gettext("Portuguese (Brazil)"),
2966
		"ru" => gettext("Russian"),
2967
		"es" => gettext("Spanish"),
2968
		"es_AR" => gettext("Spanish (Argentina)"),
2969
	);
2970

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

    
2975
	//asort($locales);
2976

    
2977
	return $locales;
2978
}
2979

    
2980
function return_hex_ipv4($ipv4) {
2981
	if (!is_ipaddrv4($ipv4)) {
2982
		return(false);
2983
	}
2984

    
2985
	/* we need the hex form of the interface IPv4 address */
2986
	$ip4arr = explode(".", $ipv4);
2987
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
2988
}
2989

    
2990
function convert_ipv6_to_128bit($ipv6) {
2991
	if (!is_ipaddrv6($ipv6)) {
2992
		return(false);
2993
	}
2994

    
2995
	$ip6arr = array();
2996
	$ip6prefix = Net_IPv6::uncompress($ipv6);
2997
	$ip6arr = explode(":", $ip6prefix);
2998
	/* binary presentation of the prefix for all 128 bits. */
2999
	$ip6prefixbin = "";
3000
	foreach ($ip6arr as $element) {
3001
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3002
	}
3003
	return($ip6prefixbin);
3004
}
3005

    
3006
function convert_128bit_to_ipv6($ip6bin) {
3007
	if (strlen($ip6bin) <> 128) {
3008
		return(false);
3009
	}
3010

    
3011
	$ip6arr = array();
3012
	$ip6binarr = array();
3013
	$ip6binarr = str_split($ip6bin, 16);
3014
	foreach ($ip6binarr as $binpart) {
3015
		$ip6arr[] = dechex(bindec($binpart));
3016
	}
3017
	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
3018

    
3019
	return($ip6addr);
3020
}
3021

    
3022

    
3023
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3024
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3025
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3026
/* 6to4 is 16 bits, e.g. 65535 */
3027
function calculate_ipv6_delegation_length($if) {
3028
	global $config;
3029

    
3030
	if (!is_array($config['interfaces'][$if])) {
3031
		return false;
3032
	}
3033

    
3034
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3035
		case "6to4":
3036
			$pdlen = 16;
3037
			break;
3038
		case "6rd":
3039
			$rd6cfg = $config['interfaces'][$if];
3040
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3041
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
3042
			break;
3043
		case "dhcp6":
3044
			$dhcp6cfg = $config['interfaces'][$if];
3045
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3046
			break;
3047
		default:
3048
			$pdlen = 0;
3049
			break;
3050
	}
3051
	return($pdlen);
3052
}
3053

    
3054
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3055
	$prefix = Net_IPv6::uncompress($prefix, true);
3056
	$suffix = Net_IPv6::uncompress($suffix, true);
3057

    
3058
	/*
3059
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3060
	 *                ^^^^ ^
3061
	 *                |||| \-> 64
3062
	 *                |||\---> 63, 62, 61, 60
3063
	 *                ||\----> 56
3064
	 *                |\-----> 52
3065
	 *                \------> 48
3066
	 */
3067

    
3068
	switch ($len) {
3069
	case 48:
3070
		$prefix_len = 15;
3071
		break;
3072
	case 52:
3073
		$prefix_len = 16;
3074
		break;
3075
	case 56:
3076
		$prefix_len = 17;
3077
		break;
3078
	case 59:
3079
	case 60:
3080
		$prefix_len = 18;
3081
		break;
3082
	/*
3083
	 * XXX 63, 62 and 61 should use 18 but PD can change and if
3084
	 * we let user chose this bit it can end up out of PD network
3085
	 *
3086
	 * Leave this with 20 for now until we find a way to let user
3087
	 * chose it. The side-effect is users with PD with one of these
3088
	 * lengths will not be able to setup DHCP server range for full
3089
	 * PD size, only for last /64 network
3090
	 */
3091
	case 63:
3092
	case 62:
3093
	case 61:
3094
	default:
3095
		$prefix_len = 20;
3096
		break;
3097
	}
3098

    
3099
	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
3100
	    substr($suffix, $prefix_len));
3101
}
3102

    
3103
function dhcpv6_pd_str_help($pdlen) {
3104
	$result = '';
3105

    
3106
	switch ($pdlen) {
3107
	case 48:
3108
		$result = '::xxxx:xxxx:xxxx:xxxx:xxxx';
3109
		break;
3110
	case 52:
3111
		$result = '::xxx:xxxx:xxxx:xxxx:xxxx';
3112
		break;
3113
	case 56:
3114
		$result = '::xx:xxxx:xxxx:xxxx:xxxx';
3115
		break;
3116
	case 59:
3117
	case 60:
3118
		$result = '::x:xxxx:xxxx:xxxx:xxxx';
3119
		break;
3120
	/*
3121
	 * XXX 63, 62 and 61 should use same mask as 60 but if
3122
	 * we let the user choose this bit it can end up out of PD network
3123
	 *
3124
	 * Leave this with the same as 64 for now until we find a way to
3125
	 * let the user choose it. The side-effect is users with PD with one
3126
	 * of these lengths will not be able to setup DHCP server ranges
3127
	 * for full PD size, only for last /64 network
3128
	 */
3129
	case 61:
3130
	case 62:
3131
	case 63:
3132
	case 64:
3133
	default:
3134
		$result = '::xxxx:xxxx:xxxx:xxxx';
3135
		break;
3136
	}
3137

    
3138
	return $result;
3139
}
3140

    
3141
function huawei_rssi_to_string($rssi) {
3142
	$dbm = array();
3143
	$i = 0;
3144
	$dbstart = -113;
3145
	while ($i < 32) {
3146
		$dbm[$i] = $dbstart + ($i * 2);
3147
		$i++;
3148
	}
3149
	$percent = round(($rssi / 31) * 100);
3150
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3151
	return $string;
3152
}
3153

    
3154
function huawei_mode_to_string($mode, $submode) {
3155
	$modes[0] = gettext("None");
3156
	$modes[1] = "AMPS";
3157
	$modes[2] = "CDMA";
3158
	$modes[3] = "GSM/GPRS";
3159
	$modes[4] = "HDR";
3160
	$modes[5] = "WCDMA";
3161
	$modes[6] = "GPS";
3162

    
3163
	$submodes[0] = gettext("No Service");
3164
	$submodes[1] = "GSM";
3165
	$submodes[2] = "GPRS";
3166
	$submodes[3] = "EDGE";
3167
	$submodes[4] = "WCDMA";
3168
	$submodes[5] = "HSDPA";
3169
	$submodes[6] = "HSUPA";
3170
	$submodes[7] = "HSDPA+HSUPA";
3171
	$submodes[8] = "TD-SCDMA";
3172
	$submodes[9] = "HSPA+";
3173
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3174
	return $string;
3175
}
3176

    
3177
function huawei_service_to_string($state) {
3178
	$modes[0] = gettext("No Service");
3179
	$modes[1] = gettext("Restricted Service");
3180
	$modes[2] = gettext("Valid Service");
3181
	$modes[3] = gettext("Restricted Regional Service");
3182
	$modes[4] = gettext("Powersaving Service");
3183
	$modes[255] = gettext("Unknown Service");
3184
	$string = $modes[$state];
3185
	return $string;
3186
}
3187

    
3188
function huawei_simstate_to_string($state) {
3189
	$modes[0] = gettext("Invalid SIM/locked State");
3190
	$modes[1] = gettext("Valid SIM State");
3191
	$modes[2] = gettext("Invalid SIM CS State");
3192
	$modes[3] = gettext("Invalid SIM PS State");
3193
	$modes[4] = gettext("Invalid SIM CS/PS State");
3194
	$modes[255] = gettext("Missing SIM State");
3195
	$string = $modes[$state];
3196
	return $string;
3197
}
3198

    
3199
function zte_rssi_to_string($rssi) {
3200
	return huawei_rssi_to_string($rssi);
3201
}
3202

    
3203
function zte_mode_to_string($mode, $submode) {
3204
	$modes[0] = gettext("No Service");
3205
	$modes[1] = gettext("Limited Service");
3206
	$modes[2] = "GPRS";
3207
	$modes[3] = "GSM";
3208
	$modes[4] = "UMTS";
3209
	$modes[5] = "EDGE";
3210
	$modes[6] = "HSDPA";
3211

    
3212
	$submodes[0] = "CS_ONLY";
3213
	$submodes[1] = "PS_ONLY";
3214
	$submodes[2] = "CS_PS";
3215
	$submodes[3] = "CAMPED";
3216
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3217
	return $string;
3218
}
3219

    
3220
function zte_service_to_string($service) {
3221
	$modes[0] = gettext("Initializing Service");
3222
	$modes[1] = gettext("Network Lock error Service");
3223
	$modes[2] = gettext("Network Locked Service");
3224
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3225
	$string = $modes[$service];
3226
	return $string;
3227
}
3228

    
3229
function zte_simstate_to_string($state) {
3230
	$modes[0] = gettext("No action State");
3231
	$modes[1] = gettext("Network lock State");
3232
	$modes[2] = gettext("(U)SIM card lock State");
3233
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3234
	$string = $modes[$state];
3235
	return $string;
3236
}
3237

    
3238
function get_configured_pppoe_server_interfaces() {
3239
	global $config;
3240
	$iflist = array();
3241
	if (is_array($config['pppoes']['pppoe'])) {
3242
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3243
			if ($pppoe['mode'] == "server") {
3244
				$int = "poes". $pppoe['pppoeid'];
3245
				$iflist[$int] = strtoupper($int);
3246
			}
3247
		}
3248
	}
3249
	return $iflist;
3250
}
3251

    
3252
function get_pppoes_child_interfaces($ifpattern) {
3253
	$if_arr = array();
3254
	if ($ifpattern == "") {
3255
		return;
3256
	}
3257

    
3258
	exec("/sbin/ifconfig", $out, $ret);
3259
	foreach ($out as $line) {
3260
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3261
			$if_arr[] = $match[1];
3262
		}
3263
	}
3264
	return $if_arr;
3265

    
3266
}
3267

    
3268
/****f* pfsense-utils/pkg_call_plugins
3269
 * NAME
3270
 *   pkg_call_plugins
3271
 * INPUTS
3272
 *   $plugin_type value used to search in package configuration if the plugin is used, also used to create the function name
3273
 *   $plugin_params parameters to pass to the plugin function for passing multiple parameters a array can be used.
3274
 * RESULT
3275
 *   returns associative array results from the plugin calls for each package
3276
 * NOTES
3277
 *   This generic function can be used to notify or retrieve results from functions that are defined in packages.
3278
 ******/
3279
function pkg_call_plugins($plugin_type, $plugin_params) {
3280
	global $g, $config;
3281
	$results = array();
3282
	if (!is_array($config['installedpackages']['package'])) {
3283
		return $results;
3284
	}
3285
	foreach ($config['installedpackages']['package'] as $package) {
3286
		if (is_array($package['plugins']['item'])) {
3287
			foreach ($package['plugins']['item'] as $plugin) {
3288
				if ($plugin['type'] == $plugin_type) {
3289
					if (file_exists($package['include_file'])) {
3290
						require_once($package['include_file']);
3291
					} else {
3292
						continue;
3293
					}
3294
					$pkgname = substr(reverse_strrchr($package['configurationfile'], "."), 0, -1);
3295
					$plugin_function = $pkgname . '_'. $plugin_type;
3296
					$results[$pkgname] = call_user_func($plugin_function, $plugin_params);
3297
				}
3298
			}
3299
		}
3300
	}
3301
	return $results;
3302
}
3303

    
3304
// Convert IPv6 addresses to lower case
3305
function addrtolower($ip) {
3306
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3307
		return(strtolower($ip));
3308
	} else {
3309
		return($ip);
3310
	}
3311
}
3312

    
3313
function compare_by_name($a, $b) {
3314
	return strcasecmp($a['name'], $b['name']);
3315
}
3316
?>
(32-32/54)