Project

General

Profile

Download (99.1 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * pfsense-utils.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2016 Rubicon Communications, LLC (Netgate)
7
 * All rights reserved.
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions are met:
11
 *
12
 * 1. Redistributions of source code must retain the above copyright notice,
13
 *    this list of conditions and the following disclaimer.
14
 *
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in
17
 *    the documentation and/or other materials provided with the
18
 *    distribution.
19
 *
20
 * 3. All advertising materials mentioning features or use of this software
21
 *    must display the following acknowledgment:
22
 *    "This product includes software developed by the pfSense Project
23
 *    for use in the pfSense® software distribution. (http://www.pfsense.org/).
24
 *
25
 * 4. The names "pfSense" and "pfSense Project" must not be used to
26
 *    endorse or promote products derived from this software without
27
 *    prior written permission. For written permission, please contact
28
 *    coreteam@pfsense.org.
29
 *
30
 * 5. Products derived from this software may not be called "pfSense"
31
 *    nor may "pfSense" appear in their names without prior written
32
 *    permission of the Electric Sheep Fencing, LLC.
33
 *
34
 * 6. Redistributions of any form whatsoever must retain the following
35
 *    acknowledgment:
36
 *
37
 * "This product includes software developed by the pfSense Project
38
 * for use in the pfSense software distribution (http://www.pfsense.org/).
39
 *
40
 * THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
41
 * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
44
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51
 * OF THE POSSIBILITY OF SUCH DAMAGE.
52
 */
53

    
54
/****f* pfsense-utils/have_natpfruleint_access
55
 * NAME
56
 *   have_natpfruleint_access
57
 * INPUTS
58
 *	none
59
 * RESULT
60
 *   returns true if user has access to edit a specific firewall nat port forward interface
61
 ******/
62
function have_natpfruleint_access($if) {
63
	$security_url = "firewall_nat_edit.php?if=". strtolower($if);
64
	if (isAllowedPage($security_url, $allowed)) {
65
		return true;
66
	}
67
	return false;
68
}
69

    
70
/****f* pfsense-utils/have_ruleint_access
71
 * NAME
72
 *   have_ruleint_access
73
 * INPUTS
74
 *	none
75
 * RESULT
76
 *   returns true if user has access to edit a specific firewall interface
77
 ******/
78
function have_ruleint_access($if) {
79
	$security_url = "firewall_rules.php?if=". strtolower($if);
80
	if (isAllowedPage($security_url)) {
81
		return true;
82
	}
83
	return false;
84
}
85

    
86
/****f* pfsense-utils/does_url_exist
87
 * NAME
88
 *   does_url_exist
89
 * INPUTS
90
 *	none
91
 * RESULT
92
 *   returns true if a url is available
93
 ******/
94
function does_url_exist($url) {
95
	$fd = fopen("$url", "r");
96
	if ($fd) {
97
		fclose($fd);
98
		return true;
99
	} else {
100
		return false;
101
	}
102
}
103

    
104
/****f* pfsense-utils/is_private_ip
105
 * NAME
106
 *   is_private_ip
107
 * INPUTS
108
 *	none
109
 * RESULT
110
 *   returns true if an ip address is in a private range
111
 ******/
112
function is_private_ip($iptocheck) {
113
	$isprivate = false;
114
	$ip_private_list = array(
115
		"10.0.0.0/8",
116
		"100.64.0.0/10",
117
		"172.16.0.0/12",
118
		"192.168.0.0/16",
119
	);
120
	foreach ($ip_private_list as $private) {
121
		if (ip_in_subnet($iptocheck, $private) == true) {
122
			$isprivate = true;
123
		}
124
	}
125
	return $isprivate;
126
}
127

    
128
/****f* pfsense-utils/get_tmp_file
129
 * NAME
130
 *   get_tmp_file
131
 * INPUTS
132
 *	none
133
 * RESULT
134
 *   returns a temporary filename
135
 ******/
136
function get_tmp_file() {
137
	global $g;
138
	return "{$g['tmp_path']}/tmp-" . time();
139
}
140

    
141
/****f* pfsense-utils/get_dns_servers
142
 * NAME
143
 *   get_dns_servers - get system dns servers
144
 * INPUTS
145
 *   none
146
 * RESULT
147
 *   $dns_servers - an array of the dns servers
148
 ******/
149
function get_dns_servers() {
150
	$dns_servers = array();
151
	if (file_exists("/etc/resolv.conf")) {
152
		$dns_s = file("/etc/resolv.conf", FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
153
	}
154
	if (is_array($dns_s)) {
155
		foreach ($dns_s as $dns) {
156
			$matches = "";
157
			if (preg_match("/nameserver (.*)/", $dns, $matches)) {
158
				$dns_servers[] = $matches[1];
159
			}
160
		}
161
	}
162
	return array_unique($dns_servers);
163
}
164

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

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

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

    
183
		foreach ($cssfiles as $css) {
184
			if (strpos($css, "BETA") != 0) {
185
				array_push($betacss, $css);
186
			} else if (strpos($css, "pfSense") != 0) {
187
				array_push($pfscss, $css);
188
			} else {
189
				array_push($usrcss, $css);
190
			}
191
		}
192

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

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

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

    
214
	$csslist = get_css_files();
215

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
385
	$section->addInput(new Form_Checkbox(
386
		'pagenamefirst',
387
		'Browser tab text',
388
		'Display page name first in browser tab',
389
		$value
390
	))->setHelp('When this is unchecked, the browser tab shows the host name followed '.
391
		'by the current page. Check this box to display the current page followed by the '.
392
		'host name.');
393
}
394

    
395
/****f* pfsense-utils/gen_user_settings_fields
396
 * NAME
397
 *   gen_user_settings_fields
398
 * INPUTS
399
 *   Pointer to section object
400
 *   Array of initial values for the fields
401
 * RESULT
402
 *   no return value, section object is updated
403
 ******/
404
function gen_user_settings_fields(&$section, $pconfig) {
405

    
406
	gen_webguicss_field($section, $pconfig['webguicss']);
407
	gen_webguifixedmenu_field($section, $pconfig['webguifixedmenu']);
408
	gen_webguihostnamemenu_field($section, $pconfig['webguihostnamemenu']);
409
	gen_dashboardcolumns_field($section, $pconfig['dashboardcolumns']);
410
	gen_interfacessort_field($section, $pconfig['interfacessort']);
411
	gen_associatedpanels_fields(
412
		$section,
413
		$pconfig['dashboardavailablewidgetspanel'],
414
		$pconfig['systemlogsfilterpanel'],
415
		$pconfig['systemlogsmanagelogpanel'],
416
		$pconfig['statusmonitoringsettingspanel']);
417
	gen_webguileftcolumnhyper_field($section, $pconfig['webguileftcolumnhyper']);
418
	gen_pagenamefirst_field($section, $pconfig['pagenamefirst']);
419
}
420

    
421
/****f* pfsense-utils/gen_requirestatefilter_field
422
 * NAME
423
 *   gen_requirestatefilter_field
424
 * INPUTS
425
 *   Pointer to section object
426
 *   Initial value for the field
427
 * RESULT
428
 *   no return value, section object is updated
429
 ******/
430
function gen_requirestatefilter_field(&$section, $value) {
431
	$section->addInput(new Form_Checkbox(
432
		'requirestatefilter',
433
		'Require State Filter',
434
		'Do not display state table without a filter',
435
		$value
436
	))->setHelp('By default, the entire state table is displayed when entering '.
437
		'Diagnostics > States. This option requires a filter to be entered '.
438
		'before the states are displayed. Useful for systems with large state tables.');
439
}
440

    
441
/****f* pfsense-utils/gen_created_updated_fields
442
 * NAME
443
 *   gen_created_updated_fields
444
 * INPUTS
445
 *   Pointer to form object
446
 *   Array of created time and username
447
 *   Array of updated time and username
448
 * RESULT
449
 *   no return value, section object is added to form if needed
450
 ******/
451
function gen_created_updated_fields(&$form, $created, $updated) {
452
	$has_created_time = (isset($created['time']) && isset($created['username']));
453
	$has_updated_time = (isset($updated['time']) && isset($updated['username']));
454

    
455
	if ($has_created_time || $has_updated_time) {
456
		$section = new Form_Section('Rule Information');
457

    
458
		if ($has_created_time) {
459
			$section->addInput(new Form_StaticText(
460
				'Created',
461
				sprintf(
462
					gettext('%1$s by %2$s'),
463
					date(gettext("n/j/y H:i:s"), $created['time']),
464
					$created['username'])
465
			));
466
		}
467

    
468
		if ($has_updated_time) {
469
			$section->addInput(new Form_StaticText(
470
				'Updated',
471
				sprintf(
472
					gettext('%1$s by %2$s'),
473
					date(gettext("n/j/y H:i:s"), $updated['time']),
474
					$updated['username'])
475
			));
476
		}
477

    
478
		$form->add($section);
479
	}
480
}
481

    
482
function hardware_offloading_applyflags($iface) {
483
	global $config;
484

    
485
	$flags_on = 0;
486
	$flags_off = 0;
487
	$options = pfSense_get_interface_addresses($iface);
488

    
489
	if (isset($config['system']['disablechecksumoffloading'])) {
490
		if (isset($options['encaps']['txcsum'])) {
491
			$flags_off |= IFCAP_TXCSUM;
492
		}
493
		if (isset($options['encaps']['rxcsum'])) {
494
			$flags_off |= IFCAP_RXCSUM;
495
		}
496
		if (isset($options['encaps']['txcsum6'])) {
497
			$flags_off |= IFCAP_TXCSUM_IPV6;
498
		}
499
		if (isset($options['encaps']['rxcsum6'])) {
500
			$flags_off |= IFCAP_RXCSUM_IPV6;
501
		}
502
	} else {
503
		if (isset($options['caps']['txcsum'])) {
504
			$flags_on |= IFCAP_TXCSUM;
505
		}
506
		if (isset($options['caps']['rxcsum'])) {
507
			$flags_on |= IFCAP_RXCSUM;
508
		}
509
		if (isset($options['caps']['txcsum6'])) {
510
			$flags_on |= IFCAP_TXCSUM_IPV6;
511
		}
512
		if (isset($options['caps']['rxcsum6'])) {
513
			$flags_on |= IFCAP_RXCSUM_IPV6;
514
		}
515
	}
516

    
517
	if (isset($config['system']['disablesegmentationoffloading'])) {
518
		$flags_off |= IFCAP_TSO;
519
	} else if (isset($options['caps']['tso']) || isset($options['caps']['tso4']) || isset($options['caps']['tso6'])) {
520
		$flags_on |= IFCAP_TSO;
521
	}
522

    
523
	if (isset($config['system']['disablelargereceiveoffloading'])) {
524
		$flags_off |= IFCAP_LRO;
525
	} else if (isset($options['caps']['lro'])) {
526
		$flags_on |= IFCAP_LRO;
527
	}
528

    
529
	/* if the NIC supports polling *AND* it is enabled in the GUI */
530
	if (!isset($config['system']['polling'])) {
531
		$flags_off |= IFCAP_POLLING;
532
	} else if (isset($options['caps']['polling'])) {
533
		$flags_on |= IFCAP_POLLING;
534
	}
535

    
536
	pfSense_interface_capabilities($iface, -$flags_off);
537
	pfSense_interface_capabilities($iface, $flags_on);
538
}
539

    
540
/****f* pfsense-utils/enable_hardware_offloading
541
 * NAME
542
 *   enable_hardware_offloading - Enable a NIC's supported hardware features.
543
 * INPUTS
544
 *   $interface	- string containing the physical interface to work on.
545
 * RESULT
546
 *   null
547
 * NOTES
548
 *   This function only supports the fxp driver's loadable microcode.
549
 ******/
550
function enable_hardware_offloading($interface) {
551
	global $g, $config;
552

    
553
	$int = get_real_interface($interface);
554
	if (empty($int)) {
555
		return;
556
	}
557

    
558
	if (!isset($config['system']['do_not_use_nic_microcode'])) {
559
		/* translate wan, lan, opt -> real interface if needed */
560
		$int_family = preg_split("/[0-9]+/", $int);
561
		$supported_ints = array('fxp');
562
		if (in_array($int_family, $supported_ints)) {
563
			if (does_interface_exist($int)) {
564
				pfSense_interface_flags($int, IFF_LINK0);
565
			}
566
		}
567
	}
568

    
569
	/* This is mostly for vlans and ppp types */
570
	$realhwif = get_parent_interface($interface);
571
	if ($realhwif[0] == $int) {
572
		hardware_offloading_applyflags($int);
573
	} else {
574
		hardware_offloading_applyflags($realhwif[0]);
575
		hardware_offloading_applyflags($int);
576
	}
577
}
578

    
579
/****f* pfsense-utils/interface_supports_polling
580
 * NAME
581
 *   checks to see if an interface supports polling according to man polling
582
 * INPUTS
583
 *
584
 * RESULT
585
 *   true or false
586
 * NOTES
587
 *
588
 ******/
589
function interface_supports_polling($iface) {
590
	$opts = pfSense_get_interface_addresses($iface);
591
	if (is_array($opts) && isset($opts['caps']['polling'])) {
592
		return true;
593
	}
594

    
595
	return false;
596
}
597

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

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

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

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

    
673
/****f* pfsense-utils/setup_polling
674
 * NAME
675
 *   sets up polling
676
 * INPUTS
677
 *
678
 * RESULT
679
 *   null
680
 * NOTES
681
 *
682
 ******/
683
function setup_polling() {
684
	global $g, $config;
685

    
686
	if (isset($config['system']['polling'])) {
687
		set_single_sysctl("kern.polling.idle_poll", "1");
688
	} else {
689
		set_single_sysctl("kern.polling.idle_poll", "0");
690
	}
691

    
692
	if ($config['system']['polling_each_burst']) {
693
		set_single_sysctl("kern.polling.each_burst", $config['system']['polling_each_burst']);
694
	}
695
	if ($config['system']['polling_burst_max']) {
696
		set_single_sysctl("kern.polling.burst_max", $config['system']['polling_burst_max']);
697
	}
698
	if ($config['system']['polling_user_frac']) {
699
		set_single_sysctl("kern.polling.user_frac", $config['system']['polling_user_frac']);
700
	}
701
}
702

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

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

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

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

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

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

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

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

    
773
	return "";
774
}
775

    
776
/*
777
 * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
778
 */
779
function get_pfsync_interface_status($pfsyncinterface) {
780
	if (!does_interface_exist($pfsyncinterface)) {
781
		return;
782
	}
783

    
784
	return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
785
}
786

    
787
/*
788
 * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
789
 */
790
function add_rule_to_anchor($anchor, $rule, $label) {
791
	mwexec("echo " . escapeshellarg($rule) . " | /sbin/pfctl -a " . escapeshellarg($anchor) . ":" . escapeshellarg($label) . " -f -");
792
}
793

    
794
/*
795
 * remove_text_from_file
796
 * remove $text from file $file
797
 */
798
function remove_text_from_file($file, $text) {
799
	if (!file_exists($file) && !is_writable($file)) {
800
		return;
801
	}
802
	$filecontents = file_get_contents($file);
803
	$text = str_replace($text, "", $filecontents);
804
	@file_put_contents($file, $text);
805
}
806

    
807
/*
808
 *   after_sync_bump_adv_skew(): create skew values by 1S
809
 */
810
function after_sync_bump_adv_skew() {
811
	global $config, $g;
812
	$processed_skew = 1;
813
	$a_vip = &$config['virtualip']['vip'];
814
	foreach ($a_vip as $vipent) {
815
		if ($vipent['advskew'] <> "") {
816
			$processed_skew = 1;
817
			$vipent['advskew'] = $vipent['advskew']+1;
818
		}
819
	}
820
	if ($processed_skew == 1) {
821
		write_config(gettext("After synch increase advertising skew"));
822
	}
823
}
824

    
825
/*
826
 * get_filename_from_url($url): converts a url to its filename.
827
 */
828
function get_filename_from_url($url) {
829
	return basename($url);
830
}
831

    
832
/*
833
 *   get_dir: return an array of $dir
834
 */
835
function get_dir($dir) {
836
	$dir_array = array();
837
	$d = dir($dir);
838
	if (!is_object($d)) {
839
		return array();
840
	}
841
	while (false !== ($entry = $d->read())) {
842
		array_push($dir_array, $entry);
843
	}
844
	$d->close();
845
	return $dir_array;
846
}
847

    
848
/****f* pfsense-utils/WakeOnLan
849
 * NAME
850
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
851
 * RESULT
852
 *   true/false - true if the operation was successful
853
 ******/
854
function WakeOnLan($addr, $mac) {
855
	$addr_byte = explode(':', $mac);
856
	$hw_addr = '';
857

    
858
	for ($a = 0; $a < 6; $a++) {
859
		$hw_addr .= chr(hexdec($addr_byte[$a]));
860
	}
861

    
862
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
863

    
864
	for ($a = 1; $a <= 16; $a++) {
865
		$msg .= $hw_addr;
866
	}
867

    
868
	// send it to the broadcast address using UDP
869
	$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
870
	if ($s == false) {
871
		log_error(gettext("Error creating socket!"));
872
		log_error(sprintf(gettext("Error code is '%1\$s' - %2\$s"), socket_last_error($s), socket_strerror(socket_last_error($s))));
873
	} else {
874
		// setting a broadcast option to socket:
875
		$opt_ret = socket_set_option($s, 1, 6, TRUE);
876
		if ($opt_ret < 0) {
877
			log_error(sprintf(gettext("setsockopt() failed, error: %s"), strerror($opt_ret)));
878
		}
879
		$e = socket_sendto($s, $msg, strlen($msg), 0, $addr, 2050);
880
		socket_close($s);
881
		log_error(sprintf(gettext('Magic Packet sent (%1$s) to (%2$s) MAC=%3$s'), $e, $addr, $mac));
882
		return true;
883
	}
884

    
885
	return false;
886
}
887

    
888
/*
889
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
890
 *					 Useful for finding paths and stripping file extensions.
891
 */
892
function reverse_strrchr($haystack, $needle) {
893
	if (!is_string($haystack)) {
894
		return;
895
	}
896
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
897
}
898

    
899
/*
900
 *  backup_config_section($section): returns as an xml file string of
901
 *                                   the configuration section
902
 */
903
function backup_config_section($section_name) {
904
	global $config;
905
	$new_section = &$config[$section_name];
906
	/* generate configuration XML */
907
	$xmlconfig = dump_xml_config($new_section, $section_name);
908
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
909
	return $xmlconfig;
910
}
911

    
912
/*
913
 *  restore_config_section($section_name, new_contents): restore a configuration section,
914
 *                                                  and write the configuration out
915
 *                                                  to disk/cf.
916
 */
917
function restore_config_section($section_name, $new_contents) {
918
	global $config, $g;
919
	conf_mount_rw();
920
	$fout = fopen("{$g['tmp_path']}/tmpxml", "w");
921
	fwrite($fout, $new_contents);
922
	fclose($fout);
923

    
924
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
925
	if ($xml['pfsense']) {
926
		$xml = $xml['pfsense'];
927
	}
928
	else if ($xml['m0n0wall']) {
929
		$xml = $xml['m0n0wall'];
930
	}
931
	if ($xml[$section_name]) {
932
		$section_xml = $xml[$section_name];
933
	} else {
934
		$section_xml = -1;
935
	}
936

    
937
	@unlink($g['tmp_path'] . "/tmpxml");
938
	if ($section_xml === -1) {
939
		return false;
940
	}
941
	$config[$section_name] = &$section_xml;
942
	if (file_exists("{$g['tmp_path']}/config.cache")) {
943
		unlink("{$g['tmp_path']}/config.cache");
944
	}
945
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
946
	disable_security_checks();
947
	conf_mount_ro();
948
	return true;
949
}
950

    
951
/*
952
 *  merge_config_section($section_name, new_contents):   restore a configuration section,
953
 *                                                  and write the configuration out
954
 *                                                  to disk/cf.  But preserve the prior
955
 * 													structure if needed
956
 */
957
function merge_config_section($section_name, $new_contents) {
958
	global $config;
959
	conf_mount_rw();
960
	$fname = get_tmp_filename();
961
	$fout = fopen($fname, "w");
962
	fwrite($fout, $new_contents);
963
	fclose($fout);
964
	$section_xml = parse_xml_config($fname, $section_name);
965
	$config[$section_name] = $section_xml;
966
	unlink($fname);
967
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
968
	disable_security_checks();
969
	conf_mount_ro();
970
	return;
971
}
972

    
973
/*
974
 * rmdir_recursive($path, $follow_links=false)
975
 * Recursively remove a directory tree (rm -rf path)
976
 * This is for directories _only_
977
 */
978
function rmdir_recursive($path, $follow_links=false) {
979
	$to_do = glob($path);
980
	if (!is_array($to_do)) {
981
		$to_do = array($to_do);
982
	}
983
	foreach ($to_do as $workingdir) { // Handle wildcards by foreaching.
984
		if (file_exists($workingdir)) {
985
			if (is_dir($workingdir)) {
986
				$dir = opendir($workingdir);
987
				while ($entry = readdir($dir)) {
988
					if (is_file("$workingdir/$entry") || ((!$follow_links) && is_link("$workingdir/$entry"))) {
989
						unlink("$workingdir/$entry");
990
					} elseif (is_dir("$workingdir/$entry") && $entry != '.' && $entry != '..') {
991
						rmdir_recursive("$workingdir/$entry");
992
					}
993
				}
994
				closedir($dir);
995
				rmdir($workingdir);
996
			} elseif (is_file($workingdir)) {
997
				unlink($workingdir);
998
			}
999
		}
1000
	}
1001
	return;
1002
}
1003

    
1004
/*
1005
 * host_firmware_version(): Return the versions used in this install
1006
 */
1007
function host_firmware_version($tocheck = "") {
1008
	global $g, $config;
1009

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

    
1012
	return array(
1013
		"firmware" => array("version" => $g['product_version']),
1014
		"kernel"   => array("version" => $os_version),
1015
		"base"     => array("version" => $os_version),
1016
		"platform" => trim(file_get_contents('/etc/platform', " \n")),
1017
		"config_version" => $config['version']
1018
	);
1019
}
1020

    
1021
function get_disk_info() {
1022
	$diskout = "";
1023
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
1024
	return explode(' ', $diskout[0]);
1025
}
1026

    
1027
/****f* pfsense-utils/strncpy
1028
 * NAME
1029
 *   strncpy - copy strings
1030
 * INPUTS
1031
 *   &$dst, $src, $length
1032
 * RESULT
1033
 *   none
1034
 ******/
1035
function strncpy(&$dst, $src, $length) {
1036
	if (strlen($src) > $length) {
1037
		$dst = substr($src, 0, $length);
1038
	} else {
1039
		$dst = $src;
1040
	}
1041
}
1042

    
1043
/****f* pfsense-utils/reload_interfaces_sync
1044
 * NAME
1045
 *   reload_interfaces - reload all interfaces
1046
 * INPUTS
1047
 *   none
1048
 * RESULT
1049
 *   none
1050
 ******/
1051
function reload_interfaces_sync() {
1052
	global $config, $g;
1053

    
1054
	if ($g['debug']) {
1055
		log_error(gettext("reload_interfaces_sync() is starting."));
1056
	}
1057

    
1058
	/* parse config.xml again */
1059
	$config = parse_config(true);
1060

    
1061
	/* enable routing */
1062
	system_routing_enable();
1063
	if ($g['debug']) {
1064
		log_error(gettext("Enabling system routing"));
1065
	}
1066

    
1067
	if ($g['debug']) {
1068
		log_error(gettext("Cleaning up Interfaces"));
1069
	}
1070

    
1071
	/* set up interfaces */
1072
	interfaces_configure();
1073
}
1074

    
1075
/****f* pfsense-utils/reload_all
1076
 * NAME
1077
 *   reload_all - triggers a reload of all settings
1078
 *   * INPUTS
1079
 *   none
1080
 * RESULT
1081
 *   none
1082
 ******/
1083
function reload_all() {
1084
	send_event("service reload all");
1085
}
1086

    
1087
/****f* pfsense-utils/reload_interfaces
1088
 * NAME
1089
 *   reload_interfaces - triggers a reload of all interfaces
1090
 * INPUTS
1091
 *   none
1092
 * RESULT
1093
 *   none
1094
 ******/
1095
function reload_interfaces() {
1096
	send_event("interface all reload");
1097
}
1098

    
1099
/****f* pfsense-utils/reload_all_sync
1100
 * NAME
1101
 *   reload_all - reload all settings
1102
 *   * INPUTS
1103
 *   none
1104
 * RESULT
1105
 *   none
1106
 ******/
1107
function reload_all_sync() {
1108
	global $config, $g;
1109

    
1110
	/* parse config.xml again */
1111
	$config = parse_config(true);
1112

    
1113
	/* set up our timezone */
1114
	system_timezone_configure();
1115

    
1116
	/* set up our hostname */
1117
	system_hostname_configure();
1118

    
1119
	/* make hosts file */
1120
	system_hosts_generate();
1121

    
1122
	/* generate resolv.conf */
1123
	system_resolvconf_generate();
1124

    
1125
	/* enable routing */
1126
	system_routing_enable();
1127

    
1128
	/* set up interfaces */
1129
	interfaces_configure();
1130

    
1131
	/* start dyndns service */
1132
	services_dyndns_configure();
1133

    
1134
	/* configure cron service */
1135
	configure_cron();
1136

    
1137
	/* start the NTP client */
1138
	system_ntp_configure();
1139

    
1140
	/* sync pw database */
1141
	conf_mount_rw();
1142
	unlink_if_exists("/etc/spwd.db.tmp");
1143
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
1144
	conf_mount_ro();
1145

    
1146
	/* restart sshd */
1147
	send_event("service restart sshd");
1148

    
1149
	/* restart webConfigurator if needed */
1150
	send_event("service restart webgui");
1151
}
1152

    
1153
function setup_serial_port($when = "save", $path = "") {
1154
	global $g, $config;
1155
	conf_mount_rw();
1156
	$ttys_file = "{$path}/etc/ttys";
1157
	$boot_config_file = "{$path}/boot.config";
1158
	$loader_conf_file = "{$path}/boot/loader.conf";
1159
	/* serial console - write out /boot.config */
1160
	if (file_exists($boot_config_file)) {
1161
		$boot_config = file_get_contents($boot_config_file);
1162
	} else {
1163
		$boot_config = "";
1164
	}
1165

    
1166
	$serialspeed = (is_numeric($config['system']['serialspeed'])) ? $config['system']['serialspeed'] : "115200";
1167
	if ($g['platform'] != "cdrom") {
1168
		$serial_only = false;
1169
		$vga_only = false;
1170

    
1171
		$specific_platform = system_identify_specific_platform();
1172

    
1173
		if (($g['platform'] == "nanobsd") && isset($g['enableserial_force'])) {
1174
			$serial_only = true;
1175
		} elseif ($specific_platform['name'] ==  'XG-1540') {
1176
			$vga_only = true;
1177
		} elseif ($specific_platform['name'] == 'RCC-VE' ||
1178
		    $specific_platform['name'] == 'RCC' ||
1179
		    $specific_platform['name'] == 'RCC-DFF' ||
1180
		    $specific_platform['name'] == 'apu2') {
1181
			$serial_only = true;
1182
		}
1183

    
1184
		$boot_config_split = explode("\n", $boot_config);
1185
		$data = array();
1186
		foreach ($boot_config_split as $bcs) {
1187
			/* Ignore -D and -h lines now */
1188
			if (!empty($bcs) && !stristr($bcs, "-D") &&
1189
			    !stristr($bcs, "-h")) {
1190
				$data[] = $bcs;
1191
			}
1192
		}
1193
		if ($serial_only === true) {
1194
			$data[] = "-S{$serialspeed} -h";
1195
		} elseif (is_serial_enabled()) {
1196
			$data[] = "-S{$serialspeed} -D";
1197
		}
1198

    
1199
		if (empty($data)) {
1200
			@unlink($boot_conf_file);
1201
		} else {
1202
			safe_write_file($boot_config_file, $data);
1203
		}
1204

    
1205
		unset($boot_config, $boot_config_file, $boot_config_split);
1206

    
1207
		/* serial console - write out /boot/loader.conf */
1208
		if ($when == "upgrade") {
1209
			system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1210
		}
1211

    
1212
		$loader_conf = file_get_contents($loader_conf_file);
1213
		$loader_conf_split = explode("\n", $loader_conf);
1214

    
1215
		$data = array();
1216
		// Loop through and only add lines that are not empty, and which
1217
		//  do not contain a console directive.
1218
		foreach ($loader_conf_split as $bcs) {
1219
			if (!empty($bcs) &&
1220
			    (stripos($bcs, "console") === false) &&
1221
			    (stripos($bcs, "boot_multicons") === false) &&
1222
			    (stripos($bcs, "boot_serial") === false) &&
1223
			    (stripos($bcs, "hw.usb.no_pf") === false) &&
1224
			    (stripos($bcs, "hint.uart.0.flags") === false) &&
1225
			    (stripos($bcs, "hint.uart.1.flags") === false)) {
1226
				$data[] = $bcs;
1227
			}
1228
		}
1229

    
1230
		if ($serial_only === true) {
1231
			$data[] = 'boot_serial="YES"';
1232
			$data[] = 'console="comconsole"';
1233
		} elseif ($vga_only === true) {
1234
			$data[] = 'console="vidconsole"';
1235
		} elseif (is_serial_enabled()) {
1236
			$data[] = 'boot_multicons="YES"';
1237
			$data[] = 'boot_serial="YES"';
1238
			$primaryconsole = isset($g['primaryconsole_force']) ?
1239
			    $g['primaryconsole_force'] :
1240
			    $config['system']['primaryconsole'];
1241
			switch ($primaryconsole) {
1242
				case "video":
1243
					$data[] = 'console="vidconsole,comconsole"';
1244
					break;
1245
				case "serial":
1246
				default:
1247
					$data[] = 'console="comconsole,vidconsole"';
1248
			}
1249
		}
1250
		$data[] = 'comconsole_speed="' . $serialspeed . '"';
1251

    
1252
		if ($specific_platform['name'] == 'RCC-VE' ||
1253
		    $specific_platform['name'] == 'RCC' ||
1254
		    $specific_platform['name'] == 'RCC-DFF') {
1255
			$data[] = 'comconsole_port="0x2F8"';
1256
			$data[] = 'hint.uart.0.flags="0x00"';
1257
			$data[] = 'hint.uart.1.flags="0x10"';
1258
		}
1259
		$data[] = 'hw.usb.no_pf="1"';
1260

    
1261
		safe_write_file($loader_conf_file, $data);
1262

    
1263
		unset($loader_conf, $loader_conf_split, $loader_config_file);
1264
	}
1265

    
1266
	$ttys = file_get_contents($ttys_file);
1267
	$ttys_split = explode("\n", $ttys);
1268

    
1269
	$data = array();
1270

    
1271
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1272

    
1273
	if (isset($config['system']['disableconsolemenu'])) {
1274
		$console_type = 'Pc';
1275
		$serial_type = 'std.' . $serialspeed;
1276
	} else {
1277
		$console_type = 'al.Pc';
1278
		$serial_type = 'al.' . $serialspeed;
1279
	}
1280

    
1281
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1282
	$ttyv0_line =
1283
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\tcons25\ton\tsecure";
1284
	$ttyu_line =
1285
	    "\"/usr/libexec/getty {$serial_type}\"\tcons25\t{$on_off}\tsecure";
1286

    
1287
	$found = array();
1288

    
1289
	foreach ($ttys_split as $tty) {
1290
		/* Ignore blank lines */
1291
		if (empty($tty)) {
1292
			continue;
1293
		}
1294

    
1295
		if (stristr($tty, "ttyv0")) {
1296
			$found['ttyv0'] = 1;
1297
			$data[] = $ttyv0_line;
1298
		} elseif (stristr($tty, "ttyu")) {
1299
			$ttyn = substr($tty, 0, 5);
1300
			$found[$ttyn] = 1;
1301
			$data[] = "{$ttyn}\t{$ttyu_line}";
1302
		} elseif (substr($tty, 0, 7) == 'console') {
1303
			$found['console'] = 1;
1304
			$data[] = $tty;
1305
		} else {
1306
			$data[] = $tty;
1307
		}
1308
	}
1309
	unset($on_off, $console_type, $serial_type);
1310

    
1311
	/* Detect missing main lines on original file and try to rebuild it */
1312
	$items = array(
1313
		'console',
1314
		'ttyv0',
1315
		'ttyu0',
1316
		'ttyu1',
1317
		'ttyu2',
1318
		'ttyu3'
1319
	);
1320

    
1321
	foreach ($items as $item) {
1322
		if (isset($found[$item])) {
1323
			continue;
1324
		}
1325

    
1326
		if ($item == 'console') {
1327
			$data[] = $console_line;
1328
		} elseif ($item == 'ttyv0') {
1329
			$data[] = $ttyv0_line;
1330
		} else {
1331
			$data[] = "{$item}\t{$ttyu_line}";
1332
		}
1333
	}
1334

    
1335
	safe_write_file($ttys_file, $data);
1336

    
1337
	unset($ttys, $ttys_file, $ttys_split, $data);
1338

    
1339
	if ($when != "upgrade") {
1340
		reload_ttys();
1341
	}
1342

    
1343
	conf_mount_ro();
1344
	return;
1345
}
1346

    
1347
function is_serial_enabled() {
1348
	global $g, $config;
1349

    
1350
	if (!isset($g['enableserial_force']) &&
1351
	    !isset($config['system']['enableserial']) &&
1352
	    ($g['platform'] == $g['product_name'] || $g['platform'] == "cdrom")) {
1353
		return false;
1354
	}
1355

    
1356
	return true;
1357
}
1358

    
1359
function reload_ttys() {
1360
	// Send a HUP signal to init will make it reload /etc/ttys
1361
	posix_kill(1, SIGHUP);
1362
}
1363

    
1364
function print_value_list($list, $count = 10, $separator = ",") {
1365
	$list = implode($separator, array_slice($list, 0, $count));
1366
	if (count($list) < $count) {
1367
		$list .= ".";
1368
	} else {
1369
		$list .= "...";
1370
	}
1371
	return $list;
1372
}
1373

    
1374
/* DHCP enabled on any interfaces? */
1375
function is_dhcp_server_enabled() {
1376
	global $config;
1377

    
1378
	if (!is_array($config['dhcpd'])) {
1379
		return false;
1380
	}
1381

    
1382
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1383
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1384
			return true;
1385
		}
1386
	}
1387

    
1388
	return false;
1389
}
1390

    
1391
/* DHCP enabled on any interfaces? */
1392
function is_dhcpv6_server_enabled() {
1393
	global $config;
1394

    
1395
	if (is_array($config['interfaces'])) {
1396
		foreach ($config['interfaces'] as $ifcfg) {
1397
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1398
				return true;
1399
			}
1400
		}
1401
	}
1402

    
1403
	if (!is_array($config['dhcpdv6'])) {
1404
		return false;
1405
	}
1406

    
1407
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1408
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1409
			return true;
1410
		}
1411
	}
1412

    
1413
	return false;
1414
}
1415

    
1416
/* radvd enabled on any interfaces? */
1417
function is_radvd_enabled() {
1418
	global $config;
1419

    
1420
	if (!is_array($config['dhcpdv6'])) {
1421
		$config['dhcpdv6'] = array();
1422
	}
1423

    
1424
	$dhcpdv6cfg = $config['dhcpdv6'];
1425
	$Iflist = get_configured_interface_list();
1426

    
1427
	/* handle manually configured DHCP6 server settings first */
1428
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1429
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1430
			continue;
1431
		}
1432

    
1433
		if (!isset($dhcpv6ifconf['ramode'])) {
1434
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1435
		}
1436

    
1437
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1438
			continue;
1439
		}
1440

    
1441
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1442
		if (!is_ipaddrv6($ifcfgipv6)) {
1443
			continue;
1444
		}
1445

    
1446
		return true;
1447
	}
1448

    
1449
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1450
	foreach ($Iflist as $if => $ifdescr) {
1451
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1452
			continue;
1453
		}
1454
		if (!isset($config['interfaces'][$if]['enable'])) {
1455
			continue;
1456
		}
1457

    
1458
		$ifcfgipv6 = get_interface_ipv6($if);
1459
		if (!is_ipaddrv6($ifcfgipv6)) {
1460
			continue;
1461
		}
1462

    
1463
		$ifcfgsnv6 = get_interface_subnetv6($if);
1464
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1465

    
1466
		if (!is_ipaddrv6($subnetv6)) {
1467
			continue;
1468
		}
1469

    
1470
		return true;
1471
	}
1472

    
1473
	return false;
1474
}
1475

    
1476
/* Any PPPoE servers enabled? */
1477
function is_pppoe_server_enabled() {
1478
	global $config;
1479

    
1480
	$pppoeenable = false;
1481

    
1482
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1483
		return false;
1484
	}
1485

    
1486
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1487
		if ($pppoes['mode'] == 'server') {
1488
			$pppoeenable = true;
1489
		}
1490
	}
1491

    
1492
	return $pppoeenable;
1493
}
1494

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

    
1509
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1510

    
1511
function get_ppp_uptime($port) {
1512
	if (file_exists("/conf/{$port}.log")) {
1513
		$saved_time = file_get_contents("/conf/{$port}.log");
1514
		$uptime_data = explode("\n", $saved_time);
1515
		$sec = 0;
1516
		foreach ($uptime_data as $upt) {
1517
			$sec += substr($upt, 1 + strpos($upt, " "));
1518
		}
1519
		return convert_seconds_to_dhms($sec);
1520
	} else {
1521
		$total_time = gettext("No history data found!");
1522
		return $total_time;
1523
	}
1524
}
1525

    
1526
//returns interface information
1527
function get_interface_info($ifdescr) {
1528
	global $config, $g;
1529

    
1530
	$ifinfo = array();
1531
	if (empty($config['interfaces'][$ifdescr])) {
1532
		return;
1533
	}
1534
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1535
	$ifinfo['if'] = get_real_interface($ifdescr);
1536

    
1537
	$chkif = $ifinfo['if'];
1538
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1539
	$ifinfo['status'] = $ifinfotmp['status'];
1540
	if (empty($ifinfo['status'])) {
1541
		$ifinfo['status'] = "down";
1542
	}
1543
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1544
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1545
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1546
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1547
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1548
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1549
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1550
	if (isset($ifinfotmp['link0'])) {
1551
		$link0 = "down";
1552
	}
1553
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1554
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1555
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1556
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1557
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1558
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1559

    
1560
	/* Use pfctl for non wrapping 64 bit counters */
1561
	/* Pass */
1562
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1563
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1564
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1565
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1566
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1567
	$in4_pass = $pf_in4_pass[5];
1568
	$out4_pass = $pf_out4_pass[5];
1569
	$in4_pass_packets = $pf_in4_pass[3];
1570
	$out4_pass_packets = $pf_out4_pass[3];
1571
	$in6_pass = $pf_in6_pass[5];
1572
	$out6_pass = $pf_out6_pass[5];
1573
	$in6_pass_packets = $pf_in6_pass[3];
1574
	$out6_pass_packets = $pf_out6_pass[3];
1575
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1576
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1577
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1578
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1579

    
1580
	/* Block */
1581
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1582
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1583
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1584
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1585
	$in4_block = $pf_in4_block[5];
1586
	$out4_block = $pf_out4_block[5];
1587
	$in4_block_packets = $pf_in4_block[3];
1588
	$out4_block_packets = $pf_out4_block[3];
1589
	$in6_block = $pf_in6_block[5];
1590
	$out6_block = $pf_out6_block[5];
1591
	$in6_block_packets = $pf_in6_block[3];
1592
	$out6_block_packets = $pf_out6_block[3];
1593
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1594
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1595
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1596
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1597

    
1598
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1599
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1600
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1601
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1602

    
1603
	$ifconfiginfo = "";
1604
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1605
	switch ($link_type) {
1606
		/* DHCP? -> see if dhclient is up */
1607
		case "dhcp":
1608
			/* see if dhclient is up */
1609
			if (find_dhclient_process($ifinfo['if']) != 0) {
1610
				$ifinfo['dhcplink'] = "up";
1611
			} else {
1612
				$ifinfo['dhcplink'] = "down";
1613
			}
1614

    
1615
			break;
1616
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1617
		case "pppoe":
1618
		case "pptp":
1619
		case "l2tp":
1620
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1621
				/* get PPPoE link status for dial on demand */
1622
				$ifinfo["{$link_type}link"] = "up";
1623
			} else {
1624
				$ifinfo["{$link_type}link"] = "down";
1625
			}
1626

    
1627
			break;
1628
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1629
		case "ppp":
1630
			if ($ifinfo['status'] == "up") {
1631
				$ifinfo['ppplink'] = "up";
1632
			} else {
1633
				$ifinfo['ppplink'] = "down" ;
1634
			}
1635

    
1636
			if (empty($ifinfo['status'])) {
1637
				$ifinfo['status'] = "down";
1638
			}
1639

    
1640
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1641
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1642
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1643
						break;
1644
					}
1645
				}
1646
			}
1647
			$dev = $ppp['ports'];
1648
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1649
				break;
1650
			}
1651
			if (!file_exists($dev)) {
1652
				$ifinfo['nodevice'] = 1;
1653
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1654
			}
1655

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

    
1691
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1692
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1693
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1694
	}
1695

    
1696
	if ($ifinfo['status'] == "up") {
1697
		/* try to determine media with ifconfig */
1698
		unset($ifconfiginfo);
1699
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1700
		$wifconfiginfo = array();
1701
		if (is_interface_wireless($ifdescr)) {
1702
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1703
			array_shift($wifconfiginfo);
1704
		}
1705
		$matches = "";
1706
		foreach ($ifconfiginfo as $ici) {
1707

    
1708
			/* don't list media/speed for wireless cards, as it always
1709
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1710
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1711
				$ifinfo['media'] = $matches[1];
1712
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1713
				$ifinfo['media'] = $matches[1];
1714
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1715
				$ifinfo['media'] = $matches[1];
1716
			}
1717

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

    
1763
	$bridge = "";
1764
	$bridge = link_interface_to_bridge($ifdescr);
1765
	if ($bridge) {
1766
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1767
		if (stristr($bridge_text, "blocking") <> false) {
1768
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1769
			$ifinfo['bridgeint'] = $bridge;
1770
		} else if (stristr($bridge_text, "learning") <> false) {
1771
			$ifinfo['bridge'] = gettext("learning");
1772
			$ifinfo['bridgeint'] = $bridge;
1773
		} else if (stristr($bridge_text, "forwarding") <> false) {
1774
			$ifinfo['bridge'] = gettext("forwarding");
1775
			$ifinfo['bridgeint'] = $bridge;
1776
		}
1777
	}
1778

    
1779
	return $ifinfo;
1780
}
1781

    
1782
//returns cpu speed of processor. Good for determining capabilities of machine
1783
function get_cpu_speed() {
1784
	return get_single_sysctl("hw.clockrate");
1785
}
1786

    
1787
function get_uptime_sec() {
1788
	$boottime = "";
1789
	$matches = "";
1790
	$boottime = get_single_sysctl("kern.boottime");
1791
	preg_match("/sec = (\d+)/", $boottime, $matches);
1792
	$boottime = $matches[1];
1793
	if (intval($boottime) == 0) {
1794
		return 0;
1795
	}
1796

    
1797
	$uptime = time() - $boottime;
1798
	return $uptime;
1799
}
1800

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

    
1834
function is_fqdn($fqdn) {
1835
	$hostname = false;
1836
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1837
		$hostname = true;
1838
	}
1839
	if (preg_match("/\.\./", $fqdn)) {
1840
		$hostname = false;
1841
	}
1842
	if (preg_match("/^\./i", $fqdn)) {
1843
		$hostname = false;
1844
	}
1845
	if (preg_match("/\//i", $fqdn)) {
1846
		$hostname = false;
1847
	}
1848
	return($hostname);
1849
}
1850

    
1851
function pfsense_default_state_size() {
1852
	/* get system memory amount */
1853
	$memory = get_memory();
1854
	$physmem = $memory[0];
1855
	/* Be cautious and only allocate 10% of system memory to the state table */
1856
	$max_states = (int) ($physmem/10)*1000;
1857
	return $max_states;
1858
}
1859

    
1860
function pfsense_default_tables_size() {
1861
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1862
	return $current;
1863
}
1864

    
1865
function pfsense_default_table_entries_size() {
1866
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1867
	return (trim($current));
1868
}
1869

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

    
1906
	if (trim($oldcontents) != trim($contents)) {
1907
		if ($g['debug']) {
1908
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1909
		}
1910
		return ($oldcontents);
1911
	} else {
1912
		return false;
1913
	}
1914
}
1915

    
1916
/*
1917
 * load_crypto() - Load crypto modules if enabled in config.
1918
 */
1919
function load_crypto() {
1920
	global $config, $g;
1921
	$crypto_modules = array('glxsb', 'aesni');
1922

    
1923
	if (!in_array($config['system']['crypto_hardware'], $crypto_modules)) {
1924
		return false;
1925
	}
1926

    
1927
	if (!empty($config['system']['crypto_hardware']) && !is_module_loaded($config['system']['crypto_hardware'])) {
1928
		log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $config['system']['crypto_hardware']));
1929
		mwexec("/sbin/kldload {$config['system']['crypto_hardware']}");
1930
	}
1931
}
1932

    
1933
/*
1934
 * load_thermal_hardware() - Load temperature monitor kernel module
1935
 */
1936
function load_thermal_hardware() {
1937
	global $config, $g;
1938
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1939

    
1940
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1941
		return false;
1942
	}
1943

    
1944
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1945
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1946
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1947
	}
1948
}
1949

    
1950
/****f* pfsense-utils/isvm
1951
 * NAME
1952
 *   isvm
1953
 * INPUTS
1954
 *	none
1955
 * RESULT
1956
 *   returns true if machine is running under a virtual environment
1957
 ******/
1958
function isvm() {
1959
	$virtualenvs = array("vmware", "parallels", "qemu", "bochs", "plex86", "VirtualBox");
1960
	$_gb = exec('/bin/kenv -q smbios.system.product 2>/dev/null', $output, $rc);
1961

    
1962
	if ($rc != 0 || !isset($output[0])) {
1963
		return false;
1964
	}
1965

    
1966
	foreach ($virtualenvs as $virtualenv) {
1967
		if (stripos($output[0], $virtualenv) !== false) {
1968
			return true;
1969
		}
1970
	}
1971

    
1972
	return false;
1973
}
1974

    
1975
function get_freebsd_version() {
1976
	$version = explode(".", php_uname("r"));
1977
	return $version[0];
1978
}
1979

    
1980
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
1981
	global $config, $g;
1982

    
1983
	$fp = fopen($destination, "wb");
1984

    
1985
	if (!$fp) {
1986
		return false;
1987
	}
1988

    
1989
	$ch = curl_init();
1990
	curl_setopt($ch, CURLOPT_URL, $url);
1991
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
1992
	curl_setopt($ch, CURLOPT_FILE, $fp);
1993
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
1994
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
1995
	curl_setopt($ch, CURLOPT_HEADER, false);
1996
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
1997
	if (!isset($config['system']['do_not_send_host_uuid'])) {
1998
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
1999
	} else {
2000
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2001
	}
2002

    
2003
	if (!empty($config['system']['proxyurl'])) {
2004
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2005
		if (!empty($config['system']['proxyport'])) {
2006
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2007
		}
2008
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2009
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2010
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2011
		}
2012
	}
2013

    
2014
	@curl_exec($ch);
2015
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2016
	fclose($fp);
2017
	curl_close($ch);
2018
	if ($http_code == 200) {
2019
		return true;
2020
	} else {
2021
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2022
		unlink_if_exists($destination);
2023
		return false;
2024
	}
2025
}
2026

    
2027
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
2028
	global $config, $g;
2029
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
2030
	$file_size = 1;
2031
	$downloaded = 1;
2032
	$first_progress_update = TRUE;
2033
	/* open destination file */
2034
	$fout = fopen($destination, "wb");
2035

    
2036
	if (!$fout) {
2037
		return false;
2038
	}
2039
	/*
2040
	 *      Originally by Author: Keyvan Minoukadeh
2041
	 *      Modified by Scott Ullrich to return Content-Length size
2042
	 */
2043
	$ch = curl_init();
2044
	curl_setopt($ch, CURLOPT_URL, $url);
2045
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2046
	curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header');
2047
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2048
	curl_setopt($ch, CURLOPT_WRITEFUNCTION, $readbody);
2049
	curl_setopt($ch, CURLOPT_NOPROGRESS, '1');
2050
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2051
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2052
	if (!isset($config['system']['do_not_send_host_uuid'])) {
2053
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ' : ' . get_single_sysctl('kern.hostuuid'));
2054
	} else {
2055
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2056
	}
2057

    
2058
	if (!empty($config['system']['proxyurl'])) {
2059
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2060
		if (!empty($config['system']['proxyport'])) {
2061
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2062
		}
2063
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2064
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2065
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2066
		}
2067
	}
2068

    
2069
	@curl_exec($ch);
2070
	$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
2071
	fclose($fout);
2072
	curl_close($ch);
2073
	if ($http_code == 200) {
2074
		return true;
2075
	} else {
2076
		log_error(sprintf(gettext('Download file failed with status code %1$s. URL: %2$s'), $http_code, $url));
2077
		unlink_if_exists($destination);
2078
		return false;
2079
	}
2080
}
2081

    
2082
function read_header($ch, $string) {
2083
	global $file_size, $fout;
2084
	$length = strlen($string);
2085
	$regs = "";
2086
	preg_match("/(Content-Length:) (.*)/", $string, $regs);
2087
	if ($regs[2] <> "") {
2088
		$file_size = intval($regs[2]);
2089
	}
2090
	ob_flush();
2091
	return $length;
2092
}
2093

    
2094
function read_body($ch, $string) {
2095
	global $fout, $file_size, $downloaded, $sendto, $static_status, $static_output, $lastseen, $first_progress_update;
2096
	global $pkg_interface;
2097
	$length = strlen($string);
2098
	$downloaded += intval($length);
2099
	if ($file_size > 0) {
2100
		$downloadProgress = round(100 * (1 - $downloaded / $file_size), 0);
2101
		$downloadProgress = 100 - $downloadProgress;
2102
	} else {
2103
		$downloadProgress = 0;
2104
	}
2105
	if ($lastseen <> $downloadProgress and $downloadProgress < 101) {
2106
		if ($sendto == "status") {
2107
			if ($pkg_interface == "console") {
2108
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2109
					$tostatus = $static_status . $downloadProgress . "%";
2110
					if ($downloadProgress == 100) {
2111
						$tostatus = $tostatus . "\r";
2112
					}
2113
					update_status($tostatus);
2114
				}
2115
			} else {
2116
				$tostatus = $static_status . $downloadProgress . "%";
2117
				update_status($tostatus);
2118
			}
2119
		} else {
2120
			if ($pkg_interface == "console") {
2121
				if (($downloadProgress % 10) == 0 || $downloadProgress < 10) {
2122
					$tooutput = $static_output . $downloadProgress . "%";
2123
					if ($downloadProgress == 100) {
2124
						$tooutput = $tooutput . "\r";
2125
					}
2126
					update_output_window($tooutput);
2127
				}
2128
			} else {
2129
				$tooutput = $static_output . $downloadProgress . "%";
2130
				update_output_window($tooutput);
2131
			}
2132
		}
2133
		if (($pkg_interface != "console") || (($downloadProgress % 10) == 0) || ($downloadProgress < 10)) {
2134
			update_progress_bar($downloadProgress, $first_progress_update);
2135
			$first_progress_update = FALSE;
2136
		}
2137
		$lastseen = $downloadProgress;
2138
	}
2139
	if ($fout) {
2140
		fwrite($fout, $string);
2141
	}
2142
	ob_flush();
2143
	return $length;
2144
}
2145

    
2146
/*
2147
 *   update_output_window: update bottom textarea dynamically.
2148
 */
2149
function update_output_window($text) {
2150
	global $pkg_interface;
2151
	$log = preg_replace("/\n/", "\\n", $text);
2152
	if ($pkg_interface != "console") {
2153
?>
2154
<script type="text/javascript">
2155
//<![CDATA[
2156
	document.getElementById("output").textContent="<?=htmlspecialchars($log)?>";
2157
	document.getElementById("output").scrollTop = document.getElementById("output").scrollHeight;
2158
//]]>
2159
</script>
2160
<?php
2161
	}
2162
	/* ensure that contents are written out */
2163
	ob_flush();
2164
}
2165

    
2166
/*
2167
 *   update_status: update top textarea dynamically.
2168
 */
2169
function update_status($status) {
2170
	global $pkg_interface;
2171

    
2172
	if ($pkg_interface == "console") {
2173
		print ("{$status}");
2174
	}
2175

    
2176
	/* ensure that contents are written out */
2177
	ob_flush();
2178
}
2179

    
2180
/*
2181
 * update_progress_bar($percent, $first_time): updates the javascript driven progress bar.
2182
 */
2183
function update_progress_bar($percent, $first_time) {
2184
	global $pkg_interface;
2185
	if ($percent > 100) {
2186
		$percent = 1;
2187
	}
2188
	if ($pkg_interface <> "console") {
2189
		echo '<script type="text/javascript">';
2190
		echo "\n//<![CDATA[\n";
2191
		echo 'document.getElementById("progressbar").style.width="'. $percent.'%"';
2192
		echo "\n//]]>\n";
2193
		echo '</script>';
2194
	} else {
2195
		if (!($first_time)) {
2196
			echo "\x08\x08\x08\x08\x08";
2197
		}
2198
		echo sprintf("%4d%%", $percent);
2199
	}
2200
}
2201

    
2202
/* Split() is being DEPRECATED as of PHP 5.3.0 and REMOVED as of PHP 6.0.0. Relying on this feature is highly discouraged. */
2203
if (!function_exists("split")) {
2204
	function split($separator, $haystack, $limit = null) {
2205
		log_error("deprecated split() call with separator '{$separator}'");
2206
		return preg_split($separator, $haystack, $limit);
2207
	}
2208
}
2209

    
2210
function update_alias_name($new_alias_name, $orig_alias_name) {
2211
	if (!$orig_alias_name) {
2212
		return;
2213
	}
2214

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

    
2241
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2242
	global $g, $config, $pconfig, $debug;
2243
	if (!$origname) {
2244
		return;
2245
	}
2246

    
2247
	$sectionref = &$config;
2248
	foreach ($section as $sectionname) {
2249
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2250
			$sectionref = &$sectionref[$sectionname];
2251
		} else {
2252
			return;
2253
		}
2254
	}
2255

    
2256
	if ($debug) {
2257
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2258
		fwrite($fd, print_r($pconfig, true));
2259
	}
2260

    
2261
	if (is_array($sectionref)) {
2262
		foreach ($sectionref as $itemkey => $item) {
2263
			if ($debug) {
2264
				fwrite($fd, "$itemkey\n");
2265
			}
2266

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

    
2286
	if ($debug) {
2287
		fclose($fd);
2288
	}
2289

    
2290
}
2291

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

    
2302
	if (!file_exists($filename)) {
2303
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2304
		return null;
2305
	}
2306

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

    
2349
function update_alias_url_data() {
2350
	global $config, $g;
2351

    
2352
	$updated = false;
2353

    
2354
	/* item is a url type */
2355
	$lockkey = lock('aliasurl');
2356
	if (is_array($config['aliases']['alias'])) {
2357
		foreach ($config['aliases']['alias'] as $x => $alias) {
2358
			if (empty($alias['aliasurl'])) {
2359
				continue;
2360
			}
2361

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

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

    
2393
	/* Report status to callers as well */
2394
	return $updated;
2395
}
2396

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

    
2427
	return true;
2428
}
2429

    
2430
function version_compare_dates($a, $b) {
2431
	$a_time = strtotime($a);
2432
	$b_time = strtotime($b);
2433

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

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

    
2518
		// First try to compare the numeric parts of the version string.
2519
		$v = version_compare_numeric($cur_num, $rem_num);
2520

    
2521
		// If the numeric parts are the same, compare the string parts.
2522
		if ($v == 0) {
2523
			return version_compare_string($cur_str, $rem_str);
2524
		}
2525
	}
2526
	return $v;
2527
}
2528
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2529
	global $g, $config;
2530

    
2531
	$urltable_prefix = "/var/db/aliastables/";
2532
	$urltable_filename = $urltable_prefix . $name . ".txt";
2533
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2534

    
2535
	// Make the aliases directory if it doesn't exist
2536
	if (!file_exists($urltable_prefix)) {
2537
		mkdir($urltable_prefix);
2538
	} elseif (!is_dir($urltable_prefix)) {
2539
		unlink($urltable_prefix);
2540
		mkdir($urltable_prefix);
2541
	}
2542

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

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

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

    
2558
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2559
			if ($type == "urltable_ports") {
2560
				$parsed_contents = group_ports($parsed_contents, true);
2561
			}
2562
			if (is_array($parsed_contents)) {
2563
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2564
			} else {
2565
				touch($urltable_filename);
2566
			}
2567

    
2568
			/* If this backup is still there on a full install, but we aren't going to use ram disks, remove the archive since this is a transition. */
2569
			if (($g['platform'] == $g['product_name']) && !isset($config['system']['use_mfs_tmpvar'])) {
2570
				unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz");
2571
			} else {
2572
				/* Update the RAM disk store with the new/updated table file. */
2573
				mwexec("cd / && /usr/bin/tar -czf \"{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz\" -C / \"{$urltable_filename}\"");
2574
			}
2575
			unlink_if_exists($tmp_urltable_filename);
2576
		} else {
2577
			if (!$validateonly) {
2578
				touch($urltable_filename);
2579
			}
2580
			conf_mount_ro();
2581
			return false;
2582
		}
2583
		conf_mount_ro();
2584
		return true;
2585
	} else {
2586
		// File exists, and it doesn't need to be updated.
2587
		return -1;
2588
	}
2589
}
2590
function get_real_slice_from_glabel($label) {
2591
	$label = escapeshellarg($label);
2592
	return trim(`/sbin/glabel list | /usr/bin/grep -B2 ufs/{$label} | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' '`);
2593
}
2594
function nanobsd_get_boot_slice() {
2595
	return trim(`/sbin/mount | /usr/bin/grep pfsense | /usr/bin/cut -d'/' -f4 | /usr/bin/cut -d' ' -f1`);
2596
}
2597
function nanobsd_get_boot_drive() {
2598
	return trim(`/sbin/glabel list | /usr/bin/grep -B2 ufs/pfsense | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' ' | /usr/bin/cut -d's' -f1`);
2599
}
2600
function nanobsd_get_active_slice() {
2601
	$boot_drive = nanobsd_get_boot_drive();
2602
	$active = trim(`gpart show $boot_drive | grep '\[active\]' | awk '{print $3;}'`);
2603

    
2604
	return "{$boot_drive}s{$active}";
2605
}
2606
function nanobsd_get_size() {
2607
	return strtoupper(file_get_contents("/etc/nanosize.txt"));
2608
}
2609
function nanobsd_switch_boot_slice() {
2610
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2611
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2612
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2613
	nanobsd_detect_slice_info();
2614

    
2615
	if ($BOOTFLASH == $ACTIVE_SLICE) {
2616
		$slice = $TOFLASH;
2617
	} else {
2618
		$slice = $BOOTFLASH;
2619
	}
2620

    
2621
	for ($i = 0; $i < ob_get_level(); $i++) {
2622
		ob_end_flush();
2623
	}
2624
	ob_implicit_flush(1);
2625
	if (strstr($slice, "s2")) {
2626
		$ASLICE = "2";
2627
		$AOLDSLICE = "1";
2628
		$AGLABEL_SLICE = "pfsense1";
2629
		$AUFS_ID = "1";
2630
		$AOLD_UFS_ID = "0";
2631
	} else {
2632
		$ASLICE = "1";
2633
		$AOLDSLICE = "2";
2634
		$AGLABEL_SLICE = "pfsense0";
2635
		$AUFS_ID = "0";
2636
		$AOLD_UFS_ID = "1";
2637
	}
2638
	$ATOFLASH = "{$BOOT_DRIVE}s{$ASLICE}";
2639
	$ACOMPLETE_PATH = "{$BOOT_DRIVE}s{$ASLICE}a";
2640
	$ABOOTFLASH = "{$BOOT_DRIVE}s{$AOLDSLICE}";
2641
	conf_mount_rw();
2642
	set_single_sysctl("kern.geom.debugflags", "16");
2643
	exec("/sbin/gpart set -a active -i {$ASLICE} {$BOOT_DRIVE}");
2644
	exec("/usr/sbin/boot0cfg -s {$ASLICE} -v /dev/{$BOOT_DRIVE}");
2645
	// We can't update these if they are mounted now.
2646
	if ($BOOTFLASH != $slice) {
2647
		exec("/sbin/tunefs -L ${AGLABEL_SLICE} /dev/$ACOMPLETE_PATH");
2648
		nanobsd_update_fstab($AGLABEL_SLICE, $ACOMPLETE_PATH, $AOLD_UFS_ID, $AUFS_ID);
2649
	}
2650
	set_single_sysctl("kern.geom.debugflags", "0");
2651
	conf_mount_ro();
2652
}
2653
function nanobsd_clone_slice() {
2654
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2655
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2656
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2657
	nanobsd_detect_slice_info();
2658

    
2659
	for ($i = 0; $i < ob_get_level(); $i++) {
2660
		ob_end_flush();
2661
	}
2662
	ob_implicit_flush(1);
2663
	set_single_sysctl("kern.geom.debugflags", "16");
2664
	exec("/bin/dd if=/dev/zero of=/dev/{$TOFLASH} bs=1m count=1");
2665
	exec("/bin/dd if=/dev/{$BOOTFLASH} of=/dev/{$TOFLASH} bs=64k");
2666
	exec("/sbin/tunefs -L {$GLABEL_SLICE} /dev/{$COMPLETE_PATH}");
2667
	$status = nanobsd_update_fstab($GLABEL_SLICE, $COMPLETE_PATH, $OLD_UFS_ID, $UFS_ID);
2668
	set_single_sysctl("kern.geom.debugflags", "0");
2669
	if ($status) {
2670
		return false;
2671
	} else {
2672
		return true;
2673
	}
2674
}
2675
function nanobsd_update_fstab($gslice, $complete_path, $oldufs, $newufs) {
2676
	$tmppath = "/tmp/{$gslice}";
2677
	$fstabpath = "/tmp/{$gslice}/etc/fstab";
2678

    
2679
	mkdir($tmppath);
2680
	exec("/sbin/fsck_ufs -y /dev/{$complete_path}");
2681
	exec("/sbin/mount /dev/ufs/{$gslice} {$tmppath}");
2682
	copy("/etc/fstab", $fstabpath);
2683

    
2684
	if (!file_exists($fstabpath)) {
2685
		$fstab = <<<EOF
2686
/dev/ufs/{$gslice} / ufs ro,noatime 1 1
2687
/dev/ufs/cf /cf ufs ro,noatime 1 1
2688
EOF;
2689
		if (file_put_contents($fstabpath, $fstab)) {
2690
			$status = true;
2691
		} else {
2692
			$status = false;
2693
		}
2694
	} else {
2695
		$status = exec("/usr/bin/sed -i \"\" \"s/pfsense{$oldufs}/pfsense{$newufs}/g\" {$fstabpath}");
2696
	}
2697
	exec("/sbin/umount {$tmppath}");
2698
	rmdir($tmppath);
2699

    
2700
	return $status;
2701
}
2702
function nanobsd_detect_slice_info() {
2703
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2704
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2705
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2706

    
2707
	$BOOT_DEVICE=nanobsd_get_boot_slice();
2708
	$REAL_BOOT_DEVICE=get_real_slice_from_glabel($BOOT_DEVICE);
2709
	$BOOT_DRIVE=nanobsd_get_boot_drive();
2710
	$ACTIVE_SLICE=nanobsd_get_active_slice();
2711

    
2712
	// Detect which slice is active and set information.
2713
	if (strstr($REAL_BOOT_DEVICE, "s1")) {
2714
		$SLICE = "2";
2715
		$OLDSLICE = "1";
2716
		$GLABEL_SLICE = "pfsense1";
2717
		$UFS_ID = "1";
2718
		$OLD_UFS_ID = "0";
2719

    
2720
	} else {
2721
		$SLICE = "1";
2722
		$OLDSLICE = "2";
2723
		$GLABEL_SLICE = "pfsense0";
2724
		$UFS_ID = "0";
2725
		$OLD_UFS_ID = "1";
2726
	}
2727
	$TOFLASH = "{$BOOT_DRIVE}s{$SLICE}";
2728
	$COMPLETE_PATH = "{$BOOT_DRIVE}s{$SLICE}a";
2729
	$COMPLETE_BOOT_PATH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2730
	$BOOTFLASH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2731
}
2732

    
2733
function nanobsd_friendly_slice_name($slicename) {
2734
	global $g;
2735
	return strtolower(str_ireplace('pfsense', $g['product_name'], $slicename));
2736
}
2737

    
2738
function get_include_contents($filename) {
2739
	if (is_file($filename)) {
2740
		ob_start();
2741
		include $filename;
2742
		$contents = ob_get_contents();
2743
		ob_end_clean();
2744
		return $contents;
2745
	}
2746
	return false;
2747
}
2748

    
2749
/* This xml 2 array function is courtesy of the php.net comment section on xml_parse.
2750
 * it is roughly 4 times faster then our existing pfSense parser but due to the large
2751
 * size of the RRD xml dumps this is required.
2752
 * The reason we do not use it for pfSense is that it does not know about array fields
2753
 * which causes it to fail on array fields with single items. Possible Todo?
2754
 */
2755
function xml2array($contents, $get_attributes = 1, $priority = 'tag') {
2756
	if (!function_exists('xml_parser_create')) {
2757
		return array ();
2758
	}
2759
	$parser = xml_parser_create('');
2760
	xml_parser_set_option($parser, XML_OPTION_TARGET_ENCODING, "UTF-8");
2761
	xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
2762
	xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
2763
	xml_parse_into_struct($parser, trim($contents), $xml_values);
2764
	xml_parser_free($parser);
2765
	if (!$xml_values) {
2766
		return; //Hmm...
2767
	}
2768
	$xml_array = array ();
2769
	$parents = array ();
2770
	$opened_tags = array ();
2771
	$arr = array ();
2772
	$current = & $xml_array;
2773
	$repeated_tag_index = array ();
2774
	foreach ($xml_values as $data) {
2775
		unset ($attributes, $value);
2776
		extract($data);
2777
		$result = array ();
2778
		$attributes_data = array ();
2779
		if (isset ($value)) {
2780
			if ($priority == 'tag') {
2781
				$result = $value;
2782
			} else {
2783
				$result['value'] = $value;
2784
			}
2785
		}
2786
		if (isset ($attributes) and $get_attributes) {
2787
			foreach ($attributes as $attr => $val) {
2788
				if ($priority == 'tag') {
2789
					$attributes_data[$attr] = $val;
2790
				} else {
2791
					$result['attr'][$attr] = $val; //Set all the attributes in a array called 'attr'
2792
				}
2793
			}
2794
		}
2795
		if ($type == "open") {
2796
			$parent[$level -1] = & $current;
2797
			if (!is_array($current) or (!in_array($tag, array_keys($current)))) {
2798
				$current[$tag] = $result;
2799
				if ($attributes_data) {
2800
					$current[$tag . '_attr'] = $attributes_data;
2801
				}
2802
				$repeated_tag_index[$tag . '_' . $level] = 1;
2803
				$current = & $current[$tag];
2804
			} else {
2805
				if (isset ($current[$tag][0])) {
2806
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2807
					$repeated_tag_index[$tag . '_' . $level]++;
2808
				} else {
2809
					$current[$tag] = array (
2810
						$current[$tag],
2811
						$result
2812
						);
2813
					$repeated_tag_index[$tag . '_' . $level] = 2;
2814
					if (isset ($current[$tag . '_attr'])) {
2815
						$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2816
						unset ($current[$tag . '_attr']);
2817
					}
2818
				}
2819
				$last_item_index = $repeated_tag_index[$tag . '_' . $level] - 1;
2820
				$current = & $current[$tag][$last_item_index];
2821
			}
2822
		} elseif ($type == "complete") {
2823
			if (!isset ($current[$tag])) {
2824
				$current[$tag] = $result;
2825
				$repeated_tag_index[$tag . '_' . $level] = 1;
2826
				if ($priority == 'tag' and $attributes_data) {
2827
					$current[$tag . '_attr'] = $attributes_data;
2828
				}
2829
			} else {
2830
				if (isset ($current[$tag][0]) and is_array($current[$tag])) {
2831
					$current[$tag][$repeated_tag_index[$tag . '_' . $level]] = $result;
2832
					if ($priority == 'tag' and $get_attributes and $attributes_data) {
2833
						$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2834
					}
2835
					$repeated_tag_index[$tag . '_' . $level]++;
2836
				} else {
2837
					$current[$tag] = array (
2838
						$current[$tag],
2839
						$result
2840
						);
2841
					$repeated_tag_index[$tag . '_' . $level] = 1;
2842
					if ($priority == 'tag' and $get_attributes) {
2843
						if (isset ($current[$tag . '_attr'])) {
2844
							$current[$tag]['0_attr'] = $current[$tag . '_attr'];
2845
							unset ($current[$tag . '_attr']);
2846
						}
2847
						if ($attributes_data) {
2848
							$current[$tag][$repeated_tag_index[$tag . '_' . $level] . '_attr'] = $attributes_data;
2849
						}
2850
					}
2851
					$repeated_tag_index[$tag . '_' . $level]++; //0 and 1 index is already taken
2852
				}
2853
			}
2854
		} elseif ($type == 'close') {
2855
			$current = & $parent[$level -1];
2856
		}
2857
	}
2858
	return ($xml_array);
2859
}
2860

    
2861
function get_country_name($country_code) {
2862
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2863
		return "";
2864
	}
2865

    
2866
	$country_names_xml = "/usr/local/share/mobile-broadband-provider-info/iso_3166-1_list_en.xml";
2867
	$country_names_contents = file_get_contents($country_names_xml);
2868
	$country_names = xml2array($country_names_contents);
2869

    
2870
	if ($country_code == "ALL") {
2871
		$country_list = array();
2872
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2873
			$country_list[] = array(
2874
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2875
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2876
		}
2877
		return $country_list;
2878
	}
2879

    
2880
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2881
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2882
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2883
		}
2884
	}
2885
	return "";
2886
}
2887

    
2888
/* sort by interface only, retain the original order of rules that apply to
2889
   the same interface */
2890
function filter_rules_sort() {
2891
	global $config;
2892

    
2893
	/* mark each rule with the sequence number (to retain the order while sorting) */
2894
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2895
		$config['filter']['rule'][$i]['seq'] = $i;
2896
	}
2897

    
2898
	usort($config['filter']['rule'], "filter_rules_compare");
2899

    
2900
	/* strip the sequence numbers again */
2901
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2902
		unset($config['filter']['rule'][$i]['seq']);
2903
	}
2904
}
2905
function filter_rules_compare($a, $b) {
2906
	if (isset($a['floating']) && isset($b['floating'])) {
2907
		return $a['seq'] - $b['seq'];
2908
	} else if (isset($a['floating'])) {
2909
		return -1;
2910
	} else if (isset($b['floating'])) {
2911
		return 1;
2912
	} else if ($a['interface'] == $b['interface']) {
2913
		return $a['seq'] - $b['seq'];
2914
	} else {
2915
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2916
	}
2917
}
2918

    
2919
function generate_ipv6_from_mac($mac) {
2920
	$elements = explode(":", $mac);
2921
	if (count($elements) <> 6) {
2922
		return false;
2923
	}
2924

    
2925
	$i = 0;
2926
	$ipv6 = "fe80::";
2927
	foreach ($elements as $byte) {
2928
		if ($i == 0) {
2929
			$hexadecimal = substr($byte, 1, 2);
2930
			$bitmap = base_convert($hexadecimal, 16, 2);
2931
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2932
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2933
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2934
		}
2935
		$ipv6 .= $byte;
2936
		if ($i == 1) {
2937
			$ipv6 .= ":";
2938
		}
2939
		if ($i == 3) {
2940
			$ipv6 .= ":";
2941
		}
2942
		if ($i == 2) {
2943
			$ipv6 .= "ff:fe";
2944
		}
2945

    
2946
		$i++;
2947
	}
2948
	return $ipv6;
2949
}
2950

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

    
2977
}
2978

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

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

    
3018
	$where_configured = array();
3019

    
3020
	$pos = strpos($ignore_if, '_virtualip');
3021
	if ($pos !== false) {
3022
		$ignore_vip_id = substr($ignore_if, $pos+10);
3023
		$ignore_vip_if = substr($ignore_if, 0, $pos);
3024
	} else {
3025
		$ignore_vip_id = -1;
3026
		$ignore_vip_if = $ignore_if;
3027
	}
3028

    
3029
	$isipv6 = is_ipaddrv6($ipaddr);
3030

    
3031
	if ($isipv6) {
3032
		$ipaddr = text_to_compressed_ip6($ipaddr);
3033
	}
3034

    
3035
	if ($check_subnets) {
3036
		$cidrprefix = intval($cidrprefix);
3037
		if ($isipv6) {
3038
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
3039
				$cidrprefix = 128;
3040
			}
3041
		} else {
3042
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
3043
				$cidrprefix = 32;
3044
			}
3045
		}
3046
		$iflist = get_configured_interface_list();
3047
		foreach ($iflist as $if => $ifname) {
3048
			if ($ignore_if == $if) {
3049
				continue;
3050
			}
3051

    
3052
			if ($isipv6) {
3053
				$if_ipv6 = get_interface_ipv6($if);
3054
				$if_snbitsv6 = get_interface_subnetv6($if);
3055
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
3056
					$where_entry = array();
3057
					$where_entry['if'] = $if;
3058
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
3059
					$where_configured[] = $where_entry;
3060
				}
3061
			} else {
3062
				$if_ipv4 = get_interface_ip($if);
3063
				$if_snbitsv4 = get_interface_subnet($if);
3064
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
3065
					$where_entry = array();
3066
					$where_entry['if'] = $if;
3067
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
3068
					$where_configured[] = $where_entry;
3069
				}
3070
			}
3071
		}
3072
	} else {
3073
		if ($isipv6) {
3074
			$interface_list_ips = get_configured_ipv6_addresses();
3075
		} else {
3076
			$interface_list_ips = get_configured_ip_addresses();
3077
		}
3078

    
3079
		foreach ($interface_list_ips as $if => $ilips) {
3080
			if ($ignore_if == $if) {
3081
				continue;
3082
			}
3083
			if (strcasecmp($ipaddr, $ilips) == 0) {
3084
				$where_entry = array();
3085
				$where_entry['if'] = $if;
3086
				$where_entry['ip_or_subnet'] = $ilips;
3087
				$where_configured[] = $where_entry;
3088
			}
3089
		}
3090
	}
3091

    
3092
	if ($check_localip) {
3093
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, text_to_compressed_ip6($config['l2tp']['localip'])) == 0)) {
3094
			$where_entry = array();
3095
			$where_entry['if'] = 'l2tp';
3096
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
3097
			$where_configured[] = $where_entry;
3098
		}
3099
	}
3100

    
3101
	return $where_configured;
3102
}
3103

    
3104
/****f* pfsense-utils/pfSense_handle_custom_code
3105
 * NAME
3106
 *   pfSense_handle_custom_code
3107
 * INPUTS
3108
 *   directory name to process
3109
 * RESULT
3110
 *   globs the directory and includes the files
3111
 */
3112
function pfSense_handle_custom_code($src_dir) {
3113
	// Allow extending of the nat edit page and include custom input validation
3114
	if (is_dir("$src_dir")) {
3115
		$cf = glob($src_dir . "/*.inc");
3116
		foreach ($cf as $nf) {
3117
			if ($nf == "." || $nf == "..") {
3118
				continue;
3119
			}
3120
			// Include the extra handler
3121
			include_once("$nf");
3122
		}
3123
	}
3124
}
3125

    
3126
function set_language() {
3127
	global $config, $g;
3128

    
3129
	if (!empty($config['system']['language'])) {
3130
		$lang = $config['system']['language'];
3131
	} elseif (!empty($g['language'])) {
3132
		$lang = $g['language'];
3133
	}
3134
	$lang .= ".UTF-8";
3135

    
3136
	putenv("LANG={$lang}");
3137
	setlocale(LC_ALL, $lang);
3138
	textdomain("pfSense");
3139
	bindtextdomain("pfSense", "/usr/local/share/locale");
3140
	bind_textdomain_codeset("pfSense", $lang);
3141
}
3142

    
3143
function get_locale_list() {
3144
	$locales = array(
3145
		"en_US" => gettext("English"),
3146
		"pt_BR" => gettext("Portuguese (Brazil)"),
3147
		"tr" => gettext("Turkish"),
3148
	);
3149
	asort($locales);
3150
	return $locales;
3151
}
3152

    
3153
function return_hex_ipv4($ipv4) {
3154
	if (!is_ipaddrv4($ipv4)) {
3155
		return(false);
3156
	}
3157

    
3158
	/* we need the hex form of the interface IPv4 address */
3159
	$ip4arr = explode(".", $ipv4);
3160
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
3161
}
3162

    
3163
function convert_ipv6_to_128bit($ipv6) {
3164
	if (!is_ipaddrv6($ipv6)) {
3165
		return(false);
3166
	}
3167

    
3168
	$ip6arr = array();
3169
	$ip6prefix = Net_IPv6::uncompress($ipv6);
3170
	$ip6arr = explode(":", $ip6prefix);
3171
	/* binary presentation of the prefix for all 128 bits. */
3172
	$ip6prefixbin = "";
3173
	foreach ($ip6arr as $element) {
3174
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3175
	}
3176
	return($ip6prefixbin);
3177
}
3178

    
3179
function convert_128bit_to_ipv6($ip6bin) {
3180
	if (strlen($ip6bin) <> 128) {
3181
		return(false);
3182
	}
3183

    
3184
	$ip6arr = array();
3185
	$ip6binarr = array();
3186
	$ip6binarr = str_split($ip6bin, 16);
3187
	foreach ($ip6binarr as $binpart) {
3188
		$ip6arr[] = dechex(bindec($binpart));
3189
	}
3190
	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
3191

    
3192
	return($ip6addr);
3193
}
3194

    
3195

    
3196
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3197
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3198
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3199
/* 6to4 is 16 bits, e.g. 65535 */
3200
function calculate_ipv6_delegation_length($if) {
3201
	global $config;
3202

    
3203
	if (!is_array($config['interfaces'][$if])) {
3204
		return false;
3205
	}
3206

    
3207
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3208
		case "6to4":
3209
			$pdlen = 16;
3210
			break;
3211
		case "6rd":
3212
			$rd6cfg = $config['interfaces'][$if];
3213
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3214
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
3215
			break;
3216
		case "dhcp6":
3217
			$dhcp6cfg = $config['interfaces'][$if];
3218
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3219
			break;
3220
		default:
3221
			$pdlen = 0;
3222
			break;
3223
	}
3224
	return($pdlen);
3225
}
3226

    
3227
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3228
	$prefix = Net_IPv6::uncompress($prefix, true);
3229
	$suffix = Net_IPv6::uncompress($suffix, true);
3230

    
3231
	/*
3232
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3233
	 *                ^^^^ ^
3234
	 *                |||| \-> 64
3235
	 *                |||\---> 63, 62, 61, 60
3236
	 *                ||\----> 56
3237
	 *                |\-----> 52
3238
	 *                \------> 48
3239
	 */
3240

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

    
3272
	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
3273
	    substr($suffix, $prefix_len));
3274
}
3275

    
3276
function dhcpv6_pd_str_help($pdlen) {
3277
	$result = '';
3278

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

    
3311
	return $result;
3312
}
3313

    
3314
function huawei_rssi_to_string($rssi) {
3315
	$dbm = array();
3316
	$i = 0;
3317
	$dbstart = -113;
3318
	while ($i < 32) {
3319
		$dbm[$i] = $dbstart + ($i * 2);
3320
		$i++;
3321
	}
3322
	$percent = round(($rssi / 31) * 100);
3323
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3324
	return $string;
3325
}
3326

    
3327
function huawei_mode_to_string($mode, $submode) {
3328
	$modes[0] = gettext("None");
3329
	$modes[1] = "AMPS";
3330
	$modes[2] = "CDMA";
3331
	$modes[3] = "GSM/GPRS";
3332
	$modes[4] = "HDR";
3333
	$modes[5] = "WCDMA";
3334
	$modes[6] = "GPS";
3335

    
3336
	$submodes[0] = gettext("No Service");
3337
	$submodes[1] = "GSM";
3338
	$submodes[2] = "GPRS";
3339
	$submodes[3] = "EDGE";
3340
	$submodes[4] = "WCDMA";
3341
	$submodes[5] = "HSDPA";
3342
	$submodes[6] = "HSUPA";
3343
	$submodes[7] = "HSDPA+HSUPA";
3344
	$submodes[8] = "TD-SCDMA";
3345
	$submodes[9] = "HSPA+";
3346
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3347
	return $string;
3348
}
3349

    
3350
function huawei_service_to_string($state) {
3351
	$modes[0] = gettext("No Service");
3352
	$modes[1] = gettext("Restricted Service");
3353
	$modes[2] = gettext("Valid Service");
3354
	$modes[3] = gettext("Restricted Regional Service");
3355
	$modes[4] = gettext("Powersaving Service");
3356
	$string = $modes[$state];
3357
	return $string;
3358
}
3359

    
3360
function huawei_simstate_to_string($state) {
3361
	$modes[0] = gettext("Invalid SIM/locked State");
3362
	$modes[1] = gettext("Valid SIM State");
3363
	$modes[2] = gettext("Invalid SIM CS State");
3364
	$modes[3] = gettext("Invalid SIM PS State");
3365
	$modes[4] = gettext("Invalid SIM CS/PS State");
3366
	$modes[255] = gettext("Missing SIM State");
3367
	$string = $modes[$state];
3368
	return $string;
3369
}
3370

    
3371
function zte_rssi_to_string($rssi) {
3372
	return huawei_rssi_to_string($rssi);
3373
}
3374

    
3375
function zte_mode_to_string($mode, $submode) {
3376
	$modes[0] = gettext("No Service");
3377
	$modes[1] = gettext("Limited Service");
3378
	$modes[2] = "GPRS";
3379
	$modes[3] = "GSM";
3380
	$modes[4] = "UMTS";
3381
	$modes[5] = "EDGE";
3382
	$modes[6] = "HSDPA";
3383

    
3384
	$submodes[0] = "CS_ONLY";
3385
	$submodes[1] = "PS_ONLY";
3386
	$submodes[2] = "CS_PS";
3387
	$submodes[3] = "CAMPED";
3388
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3389
	return $string;
3390
}
3391

    
3392
function zte_service_to_string($service) {
3393
	$modes[0] = gettext("Initializing Service");
3394
	$modes[1] = gettext("Network Lock error Service");
3395
	$modes[2] = gettext("Network Locked Service");
3396
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3397
	$string = $modes[$service];
3398
	return $string;
3399
}
3400

    
3401
function zte_simstate_to_string($state) {
3402
	$modes[0] = gettext("No action State");
3403
	$modes[1] = gettext("Network lock State");
3404
	$modes[2] = gettext("(U)SIM card lock State");
3405
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3406
	$string = $modes[$state];
3407
	return $string;
3408
}
3409

    
3410
function get_configured_pppoe_server_interfaces() {
3411
	global $config;
3412
	$iflist = array();
3413
	if (is_array($config['pppoes']['pppoe'])) {
3414
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3415
			if ($pppoe['mode'] == "server") {
3416
				$int = "poes". $pppoe['pppoeid'];
3417
				$iflist[$int] = strtoupper($int);
3418
			}
3419
		}
3420
	}
3421
	return $iflist;
3422
}
3423

    
3424
function get_pppoes_child_interfaces($ifpattern) {
3425
	$if_arr = array();
3426
	if ($ifpattern == "") {
3427
		return;
3428
	}
3429

    
3430
	exec("/sbin/ifconfig", $out, $ret);
3431
	foreach ($out as $line) {
3432
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3433
			$if_arr[] = $match[1];
3434
		}
3435
	}
3436
	return $if_arr;
3437

    
3438
}
3439

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

    
3480
function restore_aliastables() {
3481
	global $g, $config;
3482

    
3483
	$dbpath = "{$g['vardb_path']}/aliastables/";
3484

    
3485
	/* restore the alias tables, if we have them */
3486
	$files = glob("{$g['cf_conf_path']}/RAM_Disk_Store{$dbpath}*.tgz");
3487
	if (count($files)) {
3488
		echo "Restoring alias tables...";
3489
		foreach ($files as $file) {
3490
			if (file_exists($file)) {
3491
				$aliastablesrestore = "";
3492
				$aliastablesreturn = "";
3493
				exec("cd /;LANG=C /usr/bin/tar -xzf {$file} 2>&1", $aliastablesrestore, $aliastablesreturn);
3494
				$aliastablesrestore = implode(" ", $aliastablesrestore);
3495
				if ($aliastablesreturn <> 0) {
3496
					log_error(sprintf(gettext('Alias table restore failed exited with %1$s, the error is: %2$s %3$s%4$s'), $aliastablesreturn, $aliastablesrestore, $file, "\n"));
3497
				} else {
3498
					log_error(sprintf(gettext('Alias table restore succeeded exited with %1$s, the result is: %2$s %3$s%4$s'), $aliastablesreturn, $aliastablesrestore, $dbpath.basename($file, ".tgz"), "\n"));
3499
				}
3500
			}
3501
			/* If this backup is still there on a full install, but we aren't going to use ram disks, remove the archive since this is a transition. */
3502
			if (($g['platform'] == $g['product_name']) && !isset($config['system']['use_mfs_tmpvar'])) {
3503
				unlink_if_exists("{$file}");
3504
			}
3505
		}
3506
		echo "done.\n";
3507
		return true;
3508
	}
3509
	return false;
3510
}
3511

    
3512
// Convert IPv6 addresses to lower case
3513
function addrtolower($ip) {
3514
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3515
		return(strtolower($ip));
3516
	} else {
3517
		return($ip);
3518
	}
3519
}
3520
?>
(41-41/67)