Project

General

Profile

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

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

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

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

    
216
	$csslist = get_css_files();
217

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

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

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

    
241
	$section->addInput(new Form_Select(
242
		'webguifixedmenu',
243
		'Top Navigation',
244
		$value,
245
		["" => gettext("Scrolls with page"), "fixed" => gettext("Fixed (Remains visible at top of page)")]
246
	))->setHelp("The fixed option is intended for large screens only.");
247
}
248
function validate_webguifixedmenu_field(&$input_errors, $value) {
249
	$valid_values = array("", "fixed");
250
	if (!in_array($value, $valid_values)) {
251
		$input_errors[] = gettext("The submitted Top Navigation value is invalid.");
252
	}
253
}
254

    
255
/****f* pfsense-utils/gen_webguihostnamemenu_field
256
 * NAME
257
 *   gen_webguihostnamemenu_field
258
 * INPUTS
259
 *   Pointer to section object
260
 *   Initial value for the field
261
 * RESULT
262
 *   no return value, section object is updated
263
 ******/
264
function gen_webguihostnamemenu_field(&$section, $value) {
265

    
266
	$section->addInput(new Form_Select(
267
		'webguihostnamemenu',
268
		'Hostname in Menu',
269
		$value,
270
		["" => gettext("Default (No hostname)"), "hostonly" => gettext("Hostname only"), "fqdn" => gettext("Fully Qualified Domain Name")]
271
	))->setHelp("Replaces the Help menu title in the Navbar with the system hostname or FQDN.");
272
}
273
function validate_webguihostnamemenu_field(&$input_errors, $value) {
274
	$valid_values = array("", "hostonly", "fqdn");
275
	if (!in_array($value, $valid_values)) {
276
		$input_errors[] = gettext("The submitted Hostname in Menu value is invalid.");
277
	}
278
}
279

    
280
/****f* pfsense-utils/gen_dashboardcolumns_field
281
 * NAME
282
 *   gen_dashboardcolumns_field
283
 * INPUTS
284
 *   Pointer to section object
285
 *   Initial value for the field
286
 * RESULT
287
 *   no return value, section object is updated
288
 ******/
289
function gen_dashboardcolumns_field(&$section, $value) {
290

    
291
	if (((int) $value < 1) || ((int) $value > 4)) {
292
		$value = 2;
293
	}
294

    
295
	$section->addInput(new Form_Input(
296
		'dashboardcolumns',
297
		'Dashboard Columns',
298
		'number',
299
		$value,
300
		[min => 1, max => 4]
301
	));
302
}
303
function validate_dashboardcolumns_field(&$input_errors, $value) {
304
	if (!is_numericint($value) || ((int) $value < 1) || ((int) $value > 6)) {
305
		$input_errors[] = gettext("The submitted Dashboard Columns value is invalid.");
306
	}
307
}
308

    
309
/****f* pfsense-utils/gen_interfacessort_field
310
 * NAME
311
 *   gen_interfacessort_field
312
 * INPUTS
313
 *   Pointer to section object
314
 *   Initial value for the field
315
 * RESULT
316
 *   no return value, section object is updated
317
 ******/
318
function gen_interfacessort_field(&$section, $value) {
319

    
320
	$section->addInput(new Form_Checkbox(
321
		'interfacessort',
322
		'Interfaces Sort',
323
		'Sort Alphabetically',
324
		$value
325
	))->setHelp('If selected, lists of interfaces will be sorted by description, otherwise they are listed wan,lan,optn...');
326
}
327

    
328
/****f* pfsense-utils/gen_associatedpanels_fields
329
 * NAME
330
 *   gen_associatedpanels_fields
331
 * INPUTS
332
 *   Pointer to section object
333
 *   Initial value for each of the fields
334
 * RESULT
335
 *   no return value, section object is updated
336
 ******/
337
function gen_associatedpanels_fields(&$section, $value1, $value2, $value3, $value4) {
338

    
339
	$group = new Form_Group('Associated Panels Show/Hide');
340

    
341
	$group->add(new Form_Checkbox(
342
		'dashboardavailablewidgetspanel',
343
		null,
344
		'Available Widgets',
345
		$value1
346
		))->setHelp('Show the Available Widgets panel on the Dashboard.');
347

    
348
	$group->add(new Form_Checkbox(
349
		'systemlogsfilterpanel',
350
		null,
351
		'Log Filter',
352
		$value2
353
	))->setHelp('Show the Log Filter panel in System Logs.');
354

    
355
	$group->add(new Form_Checkbox(
356
		'systemlogsmanagelogpanel',
357
		null,
358
		'Manage Log',
359
		$value3
360
	))->setHelp('Show the Manage Log panel in System Logs.');
361

    
362
	$group->add(new Form_Checkbox(
363
		'statusmonitoringsettingspanel',
364
		null,
365
		'Monitoring Settings',
366
		$value4
367
	))->setHelp('Show the Settings panel in Status Monitoring.');
368

    
369
	$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.');
370

    
371
	$section->add($group);
372
}
373

    
374
/****f* pfsense-utils/gen_webguileftcolumnhyper_field
375
 * NAME
376
 *   gen_webguileftcolumnhyper_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_webguileftcolumnhyper_field(&$section, $value) {
384

    
385
	$section->addInput(new Form_Checkbox(
386
		'webguileftcolumnhyper',
387
		'Left Column Labels',
388
		'Active',
389
		$value
390
	))->setHelp('If selected, clicking a label in the left column will select/toggle the first item of the group.');
391
}
392

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

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

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

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

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

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

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

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

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

    
497
		$form->add($section);
498
	}
499
}
500

    
501
function hardware_offloading_applyflags($iface) {
502
	global $config;
503

    
504
	$flags_on = 0;
505
	$flags_off = 0;
506
	$options = pfSense_get_interface_addresses($iface);
507

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

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

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

    
548
	/* if the NIC supports polling *AND* it is enabled in the GUI */
549
	if (!isset($config['system']['polling'])) {
550
		$flags_off |= IFCAP_POLLING;
551
	} else if (isset($options['caps']['polling'])) {
552
		$flags_on |= IFCAP_POLLING;
553
	}
554

    
555
	pfSense_interface_capabilities($iface, -$flags_off);
556
	pfSense_interface_capabilities($iface, $flags_on);
557
}
558

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

    
572
	$int = get_real_interface($interface);
573
	if (empty($int)) {
574
		return;
575
	}
576

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

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

    
598
/****f* pfsense-utils/interface_supports_polling
599
 * NAME
600
 *   checks to see if an interface supports polling according to man polling
601
 * INPUTS
602
 *
603
 * RESULT
604
 *   true or false
605
 * NOTES
606
 *
607
 ******/
608
function interface_supports_polling($iface) {
609
	$opts = pfSense_get_interface_addresses($iface);
610
	if (is_array($opts) && isset($opts['caps']['polling'])) {
611
		return true;
612
	}
613

    
614
	return false;
615
}
616

    
617
/****f* pfsense-utils/is_alias_inuse
618
 * NAME
619
 *   checks to see if an alias is currently in use by a rule
620
 * INPUTS
621
 *
622
 * RESULT
623
 *   true or false
624
 * NOTES
625
 *
626
 ******/
627
function is_alias_inuse($alias) {
628
	global $g, $config;
629

    
630
	if ($alias == "") {
631
		return false;
632
	}
633
	/* loop through firewall rules looking for alias in use */
634
	if (is_array($config['filter']['rule'])) {
635
		foreach ($config['filter']['rule'] as $rule) {
636
			if ($rule['source']['address']) {
637
				if ($rule['source']['address'] == $alias) {
638
					return true;
639
				}
640
			}
641
			if ($rule['destination']['address']) {
642
				if ($rule['destination']['address'] == $alias) {
643
					return true;
644
				}
645
			}
646
		}
647
	}
648
	/* loop through nat rules looking for alias in use */
649
	if (is_array($config['nat']['rule'])) {
650
		foreach ($config['nat']['rule'] as $rule) {
651
			if ($rule['target'] && $rule['target'] == $alias) {
652
				return true;
653
			}
654
			if ($rule['source']['address'] && $rule['source']['address'] == $alias) {
655
				return true;
656
			}
657
			if ($rule['destination']['address'] && $rule['destination']['address'] == $alias) {
658
				return true;
659
			}
660
		}
661
	}
662
	return false;
663
}
664

    
665
/****f* pfsense-utils/is_schedule_inuse
666
 * NAME
667
 *   checks to see if a schedule is currently in use by a rule
668
 * INPUTS
669
 *
670
 * RESULT
671
 *   true or false
672
 * NOTES
673
 *
674
 ******/
675
function is_schedule_inuse($schedule) {
676
	global $g, $config;
677

    
678
	if ($schedule == "") {
679
		return false;
680
	}
681
	/* loop through firewall rules looking for schedule in use */
682
	if (is_array($config['filter']['rule'])) {
683
		foreach ($config['filter']['rule'] as $rule) {
684
			if ($rule['sched'] == $schedule) {
685
				return true;
686
			}
687
		}
688
	}
689
	return false;
690
}
691

    
692
/****f* pfsense-utils/setup_polling
693
 * NAME
694
 *   sets up polling
695
 * INPUTS
696
 *
697
 * RESULT
698
 *   null
699
 * NOTES
700
 *
701
 ******/
702
function setup_polling() {
703
	global $g, $config;
704

    
705
	if (isset($config['system']['polling'])) {
706
		set_single_sysctl("kern.polling.idle_poll", "1");
707
	} else {
708
		set_single_sysctl("kern.polling.idle_poll", "0");
709
	}
710

    
711
	if ($config['system']['polling_each_burst']) {
712
		set_single_sysctl("kern.polling.each_burst", $config['system']['polling_each_burst']);
713
	}
714
	if ($config['system']['polling_burst_max']) {
715
		set_single_sysctl("kern.polling.burst_max", $config['system']['polling_burst_max']);
716
	}
717
	if ($config['system']['polling_user_frac']) {
718
		set_single_sysctl("kern.polling.user_frac", $config['system']['polling_user_frac']);
719
	}
720
}
721

    
722
/****f* pfsense-utils/setup_microcode
723
 * NAME
724
 *   enumerates all interfaces and calls enable_hardware_offloading which
725
 *   enables a NIC's supported hardware features.
726
 * INPUTS
727
 *
728
 * RESULT
729
 *   null
730
 * NOTES
731
 *   This function only supports the fxp driver's loadable microcode.
732
 ******/
733
function setup_microcode() {
734

    
735
	/* if list */
736
	$iflist = get_configured_interface_list(false, true);
737
	foreach ($iflist as $if => $ifdescr) {
738
		enable_hardware_offloading($if);
739
	}
740
	unset($iflist);
741
}
742

    
743
/****f* pfsense-utils/get_carp_status
744
 * NAME
745
 *   get_carp_status - Return whether CARP is enabled or disabled.
746
 * RESULT
747
 *   boolean	- true if CARP is enabled, false if otherwise.
748
 ******/
749
function get_carp_status() {
750
	/* grab the current status of carp */
751
	$status = get_single_sysctl('net.inet.carp.allow');
752
	return (intval($status) > 0);
753
}
754

    
755
/*
756
 * convert_ip_to_network_format($ip, $subnet): converts an ip address to network form
757

    
758
 */
759
function convert_ip_to_network_format($ip, $subnet) {
760
	$ipsplit = explode('.', $ip);
761
	$string = $ipsplit[0] . "." . $ipsplit[1] . "." . $ipsplit[2] . ".0/" . $subnet;
762
	return $string;
763
}
764

    
765
/*
766
 * get_carp_interface_status($carpid): returns the status of a carp uniqid
767
 */
768
function get_carp_interface_status($carpid) {
769

    
770
	$carpiface = get_configured_vip_interface($carpid);
771
	if ($carpiface == NULL)
772
		return "";
773
	$interface = get_real_interface($carpiface);
774
	if ($interface == NULL)
775
		return "";
776
	$vip = get_configured_vip($carpid);
777
	if ($vip == NULL || !isset($vip['vhid']))
778
		return "";
779

    
780
	$vhid = $vip['vhid'];
781
	$carp_query = '';
782
	$_gb = exec("/sbin/ifconfig {$interface} | /usr/bin/grep \"carp:.* vhid {$vhid} \"", $carp_query);
783
	foreach ($carp_query as $int) {
784
		if (stripos($int, "MASTER"))
785
			return "MASTER";
786
		elseif (stripos($int, "BACKUP"))
787
			return "BACKUP";
788
		elseif (stripos($int, "INIT"))
789
			return "INIT";
790
	}
791

    
792
	return "";
793
}
794

    
795
/*
796
 * get_pfsync_interface_status($pfsyncinterface): returns the status of a pfsync
797
 */
798
function get_pfsync_interface_status($pfsyncinterface) {
799
	if (!does_interface_exist($pfsyncinterface)) {
800
		return;
801
	}
802

    
803
	return exec_command("/sbin/ifconfig {$pfsyncinterface} | /usr/bin/awk '/pfsync:/ {print \$5}'");
804
}
805

    
806
/*
807
 * add_rule_to_anchor($anchor, $rule): adds the specified rule to an anchor
808
 */
809
function add_rule_to_anchor($anchor, $rule, $label) {
810
	mwexec("echo " . escapeshellarg($rule) . " | /sbin/pfctl -a " . escapeshellarg($anchor) . ":" . escapeshellarg($label) . " -f -");
811
}
812

    
813
/*
814
 * remove_text_from_file
815
 * remove $text from file $file
816
 */
817
function remove_text_from_file($file, $text) {
818
	if (!file_exists($file) && !is_writable($file)) {
819
		return;
820
	}
821
	$filecontents = file_get_contents($file);
822
	$text = str_replace($text, "", $filecontents);
823
	@file_put_contents($file, $text);
824
}
825

    
826
/*
827
 *   after_sync_bump_adv_skew(): create skew values by 1S
828
 */
829
function after_sync_bump_adv_skew() {
830
	global $config, $g;
831
	$processed_skew = 1;
832
	$a_vip = &$config['virtualip']['vip'];
833
	foreach ($a_vip as $vipent) {
834
		if ($vipent['advskew'] <> "") {
835
			$processed_skew = 1;
836
			$vipent['advskew'] = $vipent['advskew']+1;
837
		}
838
	}
839
	if ($processed_skew == 1) {
840
		write_config(gettext("After synch increase advertising skew"));
841
	}
842
}
843

    
844
/*
845
 * get_filename_from_url($url): converts a url to its filename.
846
 */
847
function get_filename_from_url($url) {
848
	return basename($url);
849
}
850

    
851
/*
852
 *   get_dir: return an array of $dir
853
 */
854
function get_dir($dir) {
855
	$dir_array = array();
856
	$d = dir($dir);
857
	if (!is_object($d)) {
858
		return array();
859
	}
860
	while (false !== ($entry = $d->read())) {
861
		array_push($dir_array, $entry);
862
	}
863
	$d->close();
864
	return $dir_array;
865
}
866

    
867
/****f* pfsense-utils/WakeOnLan
868
 * NAME
869
 *   WakeOnLan - Wake a machine up using the wake on lan format/protocol
870
 * RESULT
871
 *   true/false - true if the operation was successful
872
 ******/
873
function WakeOnLan($addr, $mac) {
874
	$addr_byte = explode(':', $mac);
875
	$hw_addr = '';
876

    
877
	for ($a = 0; $a < 6; $a++) {
878
		$hw_addr .= chr(hexdec($addr_byte[$a]));
879
	}
880

    
881
	$msg = chr(255).chr(255).chr(255).chr(255).chr(255).chr(255);
882

    
883
	for ($a = 1; $a <= 16; $a++) {
884
		$msg .= $hw_addr;
885
	}
886

    
887
	// send it to the broadcast address using UDP
888
	$s = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
889
	if ($s == false) {
890
		log_error(gettext("Error creating socket!"));
891
		log_error(sprintf(gettext("Error code is '%1\$s' - %2\$s"), socket_last_error($s), socket_strerror(socket_last_error($s))));
892
	} else {
893
		// setting a broadcast option to socket:
894
		$opt_ret = socket_set_option($s, 1, 6, TRUE);
895
		if ($opt_ret < 0) {
896
			log_error(sprintf(gettext("setsockopt() failed, error: %s"), strerror($opt_ret)));
897
		}
898
		$e = socket_sendto($s, $msg, strlen($msg), 0, $addr, 2050);
899
		socket_close($s);
900
		log_error(sprintf(gettext('Magic Packet sent (%1$s) to (%2$s) MAC=%3$s'), $e, $addr, $mac));
901
		return true;
902
	}
903

    
904
	return false;
905
}
906

    
907
/*
908
 * reverse_strrchr($haystack, $needle):  Return everything in $haystack up to the *last* instance of $needle.
909
 *					 Useful for finding paths and stripping file extensions.
910
 */
911
function reverse_strrchr($haystack, $needle) {
912
	if (!is_string($haystack)) {
913
		return;
914
	}
915
	return strrpos($haystack, $needle) ? substr($haystack, 0, strrpos($haystack, $needle) +1) : false;
916
}
917

    
918
/*
919
 *  backup_config_section($section): returns as an xml file string of
920
 *                                   the configuration section
921
 */
922
function backup_config_section($section_name) {
923
	global $config;
924
	$new_section = &$config[$section_name];
925
	/* generate configuration XML */
926
	$xmlconfig = dump_xml_config($new_section, $section_name);
927
	$xmlconfig = str_replace("<?xml version=\"1.0\"?>", "", $xmlconfig);
928
	return $xmlconfig;
929
}
930

    
931
/*
932
 *  restore_config_section($section_name, new_contents): restore a configuration section,
933
 *                                                  and write the configuration out
934
 *                                                  to disk/cf.
935
 */
936
function restore_config_section($section_name, $new_contents) {
937
	global $config, $g;
938
	conf_mount_rw();
939
	$fout = fopen("{$g['tmp_path']}/tmpxml", "w");
940
	fwrite($fout, $new_contents);
941
	fclose($fout);
942

    
943
	$xml = parse_xml_config($g['tmp_path'] . "/tmpxml", null);
944
	if ($xml['pfsense']) {
945
		$xml = $xml['pfsense'];
946
	}
947
	else if ($xml['m0n0wall']) {
948
		$xml = $xml['m0n0wall'];
949
	}
950
	if ($xml[$section_name]) {
951
		$section_xml = $xml[$section_name];
952
	} else {
953
		$section_xml = -1;
954
	}
955

    
956
	@unlink($g['tmp_path'] . "/tmpxml");
957
	if ($section_xml === -1) {
958
		return false;
959
	}
960
	$config[$section_name] = &$section_xml;
961
	if (file_exists("{$g['tmp_path']}/config.cache")) {
962
		unlink("{$g['tmp_path']}/config.cache");
963
	}
964
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
965
	disable_security_checks();
966
	conf_mount_ro();
967
	return true;
968
}
969

    
970
/*
971
 *  merge_config_section($section_name, new_contents):   restore a configuration section,
972
 *                                                  and write the configuration out
973
 *                                                  to disk/cf.  But preserve the prior
974
 * 													structure if needed
975
 */
976
function merge_config_section($section_name, $new_contents) {
977
	global $config;
978
	conf_mount_rw();
979
	$fname = get_tmp_filename();
980
	$fout = fopen($fname, "w");
981
	fwrite($fout, $new_contents);
982
	fclose($fout);
983
	$section_xml = parse_xml_config($fname, $section_name);
984
	$config[$section_name] = $section_xml;
985
	unlink($fname);
986
	write_config(sprintf(gettext("Restored %s of config file (maybe from CARP partner)"), $section_name));
987
	disable_security_checks();
988
	conf_mount_ro();
989
	return;
990
}
991

    
992
/*
993
 * rmdir_recursive($path, $follow_links=false)
994
 * Recursively remove a directory tree (rm -rf path)
995
 * This is for directories _only_
996
 */
997
function rmdir_recursive($path, $follow_links=false) {
998
	$to_do = glob($path);
999
	if (!is_array($to_do)) {
1000
		$to_do = array($to_do);
1001
	}
1002
	foreach ($to_do as $workingdir) { // Handle wildcards by foreaching.
1003
		if (file_exists($workingdir)) {
1004
			if (is_dir($workingdir)) {
1005
				$dir = opendir($workingdir);
1006
				while ($entry = readdir($dir)) {
1007
					if (is_file("$workingdir/$entry") || ((!$follow_links) && is_link("$workingdir/$entry"))) {
1008
						unlink("$workingdir/$entry");
1009
					} elseif (is_dir("$workingdir/$entry") && $entry != '.' && $entry != '..') {
1010
						rmdir_recursive("$workingdir/$entry");
1011
					}
1012
				}
1013
				closedir($dir);
1014
				rmdir($workingdir);
1015
			} elseif (is_file($workingdir)) {
1016
				unlink($workingdir);
1017
			}
1018
		}
1019
	}
1020
	return;
1021
}
1022

    
1023
/*
1024
 * host_firmware_version(): Return the versions used in this install
1025
 */
1026
function host_firmware_version($tocheck = "") {
1027
	global $g, $config;
1028

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

    
1031
	return array(
1032
		"firmware" => array("version" => $g['product_version']),
1033
		"kernel"   => array("version" => $os_version),
1034
		"base"     => array("version" => $os_version),
1035
		"platform" => trim(file_get_contents('/etc/platform', " \n")),
1036
		"config_version" => $config['version']
1037
	);
1038
}
1039

    
1040
function get_disk_info() {
1041
	$diskout = "";
1042
	exec("/bin/df -h | /usr/bin/grep -w '/' | /usr/bin/awk '{ print $2, $3, $4, $5 }'", $diskout);
1043
	return explode(' ', $diskout[0]);
1044
}
1045

    
1046
/****f* pfsense-utils/strncpy
1047
 * NAME
1048
 *   strncpy - copy strings
1049
 * INPUTS
1050
 *   &$dst, $src, $length
1051
 * RESULT
1052
 *   none
1053
 ******/
1054
function strncpy(&$dst, $src, $length) {
1055
	if (strlen($src) > $length) {
1056
		$dst = substr($src, 0, $length);
1057
	} else {
1058
		$dst = $src;
1059
	}
1060
}
1061

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

    
1073
	if ($g['debug']) {
1074
		log_error(gettext("reload_interfaces_sync() is starting."));
1075
	}
1076

    
1077
	/* parse config.xml again */
1078
	$config = parse_config(true);
1079

    
1080
	/* enable routing */
1081
	system_routing_enable();
1082
	if ($g['debug']) {
1083
		log_error(gettext("Enabling system routing"));
1084
	}
1085

    
1086
	if ($g['debug']) {
1087
		log_error(gettext("Cleaning up Interfaces"));
1088
	}
1089

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

    
1094
/****f* pfsense-utils/reload_all
1095
 * NAME
1096
 *   reload_all - triggers a reload of all settings
1097
 *   * INPUTS
1098
 *   none
1099
 * RESULT
1100
 *   none
1101
 ******/
1102
function reload_all() {
1103
	send_event("service reload all");
1104
}
1105

    
1106
/****f* pfsense-utils/reload_interfaces
1107
 * NAME
1108
 *   reload_interfaces - triggers a reload of all interfaces
1109
 * INPUTS
1110
 *   none
1111
 * RESULT
1112
 *   none
1113
 ******/
1114
function reload_interfaces() {
1115
	send_event("interface all reload");
1116
}
1117

    
1118
/****f* pfsense-utils/reload_all_sync
1119
 * NAME
1120
 *   reload_all - reload all settings
1121
 *   * INPUTS
1122
 *   none
1123
 * RESULT
1124
 *   none
1125
 ******/
1126
function reload_all_sync() {
1127
	global $config, $g;
1128

    
1129
	/* parse config.xml again */
1130
	$config = parse_config(true);
1131

    
1132
	/* set up our timezone */
1133
	system_timezone_configure();
1134

    
1135
	/* set up our hostname */
1136
	system_hostname_configure();
1137

    
1138
	/* make hosts file */
1139
	system_hosts_generate();
1140

    
1141
	/* generate resolv.conf */
1142
	system_resolvconf_generate();
1143

    
1144
	/* enable routing */
1145
	system_routing_enable();
1146

    
1147
	/* set up interfaces */
1148
	interfaces_configure();
1149

    
1150
	/* start dyndns service */
1151
	services_dyndns_configure();
1152

    
1153
	/* configure cron service */
1154
	configure_cron();
1155

    
1156
	/* start the NTP client */
1157
	system_ntp_configure();
1158

    
1159
	/* sync pw database */
1160
	conf_mount_rw();
1161
	unlink_if_exists("/etc/spwd.db.tmp");
1162
	mwexec("/usr/sbin/pwd_mkdb -d /etc/ /etc/master.passwd");
1163
	conf_mount_ro();
1164

    
1165
	/* restart sshd */
1166
	send_event("service restart sshd");
1167

    
1168
	/* restart webConfigurator if needed */
1169
	send_event("service restart webgui");
1170
}
1171

    
1172
function setup_serial_port($when = "save", $path = "") {
1173
	global $g, $config;
1174
	conf_mount_rw();
1175
	$ttys_file = "{$path}/etc/ttys";
1176
	$boot_config_file = "{$path}/boot.config";
1177
	$loader_conf_file = "{$path}/boot/loader.conf";
1178
	/* serial console - write out /boot.config */
1179
	if (file_exists($boot_config_file)) {
1180
		$boot_config = file_get_contents($boot_config_file);
1181
	} else {
1182
		$boot_config = "";
1183
	}
1184

    
1185
	$serialspeed = (is_numeric($config['system']['serialspeed'])) ? $config['system']['serialspeed'] : "115200";
1186
	if ($g['platform'] != "cdrom") {
1187
		$serial_only = false;
1188
		$vga_only = false;
1189

    
1190
		$specific_platform = system_identify_specific_platform();
1191

    
1192
		if (($g['platform'] == "nanobsd") && isset($g['enableserial_force'])) {
1193
			$serial_only = true;
1194
		} elseif ($specific_platform['name'] ==  'XG-1540') {
1195
			$vga_only = true;
1196
		} elseif ($specific_platform['name'] == 'RCC-VE' ||
1197
		    $specific_platform['name'] == 'RCC' ||
1198
		    $specific_platform['name'] == 'RCC-DFF' ||
1199
		    $specific_platform['name'] == 'apu2') {
1200
			$serial_only = true;
1201
		}
1202

    
1203
		$boot_config_split = explode("\n", $boot_config);
1204
		$data = array();
1205
		foreach ($boot_config_split as $bcs) {
1206
			/* Ignore -D and -h lines now */
1207
			if (!empty($bcs) && !stristr($bcs, "-D") &&
1208
			    !stristr($bcs, "-h")) {
1209
				$data[] = $bcs;
1210
			}
1211
		}
1212
		if ($serial_only === true) {
1213
			$data[] = "-S{$serialspeed} -h";
1214
		} elseif (is_serial_enabled()) {
1215
			$data[] = "-S{$serialspeed} -D";
1216
		}
1217

    
1218
		if (empty($data)) {
1219
			@unlink($boot_conf_file);
1220
		} else {
1221
			safe_write_file($boot_config_file, $data);
1222
		}
1223

    
1224
		unset($boot_config, $boot_config_file, $boot_config_split);
1225

    
1226
		/* serial console - write out /boot/loader.conf */
1227
		if ($when == "upgrade") {
1228
			system("echo \"Reading {$loader_conf_file}...\" >> /conf/upgrade_log.txt");
1229
		}
1230

    
1231
		$loader_conf = file_get_contents($loader_conf_file);
1232
		$loader_conf_split = explode("\n", $loader_conf);
1233

    
1234
		$data = array();
1235
		// Loop through and only add lines that are not empty, and which
1236
		//  do not contain a console directive.
1237
		foreach ($loader_conf_split as $bcs) {
1238
			if (!empty($bcs) &&
1239
			    (stripos($bcs, "console") === false) &&
1240
			    (stripos($bcs, "boot_multicons") === false) &&
1241
			    (stripos($bcs, "boot_serial") === false) &&
1242
			    (stripos($bcs, "hw.usb.no_pf") === false) &&
1243
			    (stripos($bcs, "hint.uart.0.flags") === false) &&
1244
			    (stripos($bcs, "hint.uart.1.flags") === false)) {
1245
				$data[] = $bcs;
1246
			}
1247
		}
1248

    
1249
		if ($serial_only === true) {
1250
			$data[] = 'boot_serial="YES"';
1251
			$data[] = 'console="comconsole"';
1252
		} elseif ($vga_only === true) {
1253
			$data[] = 'console="vidconsole"';
1254
		} elseif (is_serial_enabled()) {
1255
			$data[] = 'boot_multicons="YES"';
1256
			$data[] = 'boot_serial="YES"';
1257
			$primaryconsole = isset($g['primaryconsole_force']) ?
1258
			    $g['primaryconsole_force'] :
1259
			    $config['system']['primaryconsole'];
1260
			switch ($primaryconsole) {
1261
				case "video":
1262
					$data[] = 'console="vidconsole,comconsole"';
1263
					break;
1264
				case "serial":
1265
				default:
1266
					$data[] = 'console="comconsole,vidconsole"';
1267
			}
1268
		}
1269
		$data[] = 'comconsole_speed="' . $serialspeed . '"';
1270

    
1271
		if ($specific_platform['name'] == 'RCC-VE' ||
1272
		    $specific_platform['name'] == 'RCC' ||
1273
		    $specific_platform['name'] == 'RCC-DFF') {
1274
			$data[] = 'comconsole_port="0x2F8"';
1275
			$data[] = 'hint.uart.0.flags="0x00"';
1276
			$data[] = 'hint.uart.1.flags="0x10"';
1277
		}
1278
		$data[] = 'hw.usb.no_pf="1"';
1279

    
1280
		safe_write_file($loader_conf_file, $data);
1281

    
1282
		unset($loader_conf, $loader_conf_split, $loader_config_file);
1283
	}
1284

    
1285
	$ttys = file_get_contents($ttys_file);
1286
	$ttys_split = explode("\n", $ttys);
1287

    
1288
	$data = array();
1289

    
1290
	$on_off = (is_serial_enabled() ? 'onifconsole' : 'off');
1291

    
1292
	if (isset($config['system']['disableconsolemenu'])) {
1293
		$console_type = 'Pc';
1294
		$serial_type = 'std.' . $serialspeed;
1295
	} else {
1296
		$console_type = 'al.Pc';
1297
		$serial_type = 'al.' . $serialspeed;
1298
	}
1299

    
1300
	$console_line = "console\tnone\t\t\t\tunknown\toff\tsecure";
1301
	$ttyv0_line =
1302
	    "ttyv0\t\"/usr/libexec/getty {$console_type}\"\tcons25\ton\tsecure";
1303
	$ttyu_line =
1304
	    "\"/usr/libexec/getty {$serial_type}\"\tcons25\t{$on_off}\tsecure";
1305

    
1306
	$found = array();
1307

    
1308
	foreach ($ttys_split as $tty) {
1309
		/* Ignore blank lines */
1310
		if (empty($tty)) {
1311
			continue;
1312
		}
1313

    
1314
		if (stristr($tty, "ttyv0")) {
1315
			$found['ttyv0'] = 1;
1316
			$data[] = $ttyv0_line;
1317
		} elseif (stristr($tty, "ttyu")) {
1318
			$ttyn = substr($tty, 0, 5);
1319
			$found[$ttyn] = 1;
1320
			$data[] = "{$ttyn}\t{$ttyu_line}";
1321
		} elseif (substr($tty, 0, 7) == 'console') {
1322
			$found['console'] = 1;
1323
			$data[] = $tty;
1324
		} else {
1325
			$data[] = $tty;
1326
		}
1327
	}
1328
	unset($on_off, $console_type, $serial_type);
1329

    
1330
	/* Detect missing main lines on original file and try to rebuild it */
1331
	$items = array(
1332
		'console',
1333
		'ttyv0',
1334
		'ttyu0',
1335
		'ttyu1',
1336
		'ttyu2',
1337
		'ttyu3'
1338
	);
1339

    
1340
	foreach ($items as $item) {
1341
		if (isset($found[$item])) {
1342
			continue;
1343
		}
1344

    
1345
		if ($item == 'console') {
1346
			$data[] = $console_line;
1347
		} elseif ($item == 'ttyv0') {
1348
			$data[] = $ttyv0_line;
1349
		} else {
1350
			$data[] = "{$item}\t{$ttyu_line}";
1351
		}
1352
	}
1353

    
1354
	safe_write_file($ttys_file, $data);
1355

    
1356
	unset($ttys, $ttys_file, $ttys_split, $data);
1357

    
1358
	if ($when != "upgrade") {
1359
		reload_ttys();
1360
	}
1361

    
1362
	conf_mount_ro();
1363
	return;
1364
}
1365

    
1366
function is_serial_enabled() {
1367
	global $g, $config;
1368

    
1369
	if (!isset($g['enableserial_force']) &&
1370
	    !isset($config['system']['enableserial']) &&
1371
	    ($g['platform'] == $g['product_name'] || $g['platform'] == "cdrom")) {
1372
		return false;
1373
	}
1374

    
1375
	return true;
1376
}
1377

    
1378
function reload_ttys() {
1379
	// Send a HUP signal to init will make it reload /etc/ttys
1380
	posix_kill(1, SIGHUP);
1381
}
1382

    
1383
function print_value_list($list, $count = 10, $separator = ",") {
1384
	$list = implode($separator, array_slice($list, 0, $count));
1385
	if (count($list) < $count) {
1386
		$list .= ".";
1387
	} else {
1388
		$list .= "...";
1389
	}
1390
	return $list;
1391
}
1392

    
1393
/* DHCP enabled on any interfaces? */
1394
function is_dhcp_server_enabled() {
1395
	global $config;
1396

    
1397
	if (!is_array($config['dhcpd'])) {
1398
		return false;
1399
	}
1400

    
1401
	foreach ($config['dhcpd'] as $dhcpif => $dhcpifconf) {
1402
		if (isset($dhcpifconf['enable']) && !empty($config['interfaces'][$dhcpif])) {
1403
			return true;
1404
		}
1405
	}
1406

    
1407
	return false;
1408
}
1409

    
1410
/* DHCP enabled on any interfaces? */
1411
function is_dhcpv6_server_enabled() {
1412
	global $config;
1413

    
1414
	if (is_array($config['interfaces'])) {
1415
		foreach ($config['interfaces'] as $ifcfg) {
1416
			if (isset($ifcfg['enable']) && !empty($ifcfg['track6-interface'])) {
1417
				return true;
1418
			}
1419
		}
1420
	}
1421

    
1422
	if (!is_array($config['dhcpdv6'])) {
1423
		return false;
1424
	}
1425

    
1426
	foreach ($config['dhcpdv6'] as $dhcpv6if => $dhcpv6ifconf) {
1427
		if (isset($dhcpv6ifconf['enable']) && !empty($config['interfaces'][$dhcpv6if])) {
1428
			return true;
1429
		}
1430
	}
1431

    
1432
	return false;
1433
}
1434

    
1435
/* radvd enabled on any interfaces? */
1436
function is_radvd_enabled() {
1437
	global $config;
1438

    
1439
	if (!is_array($config['dhcpdv6'])) {
1440
		$config['dhcpdv6'] = array();
1441
	}
1442

    
1443
	$dhcpdv6cfg = $config['dhcpdv6'];
1444
	$Iflist = get_configured_interface_list();
1445

    
1446
	/* handle manually configured DHCP6 server settings first */
1447
	foreach ($dhcpdv6cfg as $dhcpv6if => $dhcpv6ifconf) {
1448
		if (!isset($config['interfaces'][$dhcpv6if]['enable'])) {
1449
			continue;
1450
		}
1451

    
1452
		if (!isset($dhcpv6ifconf['ramode'])) {
1453
			$dhcpv6ifconf['ramode'] = $dhcpv6ifconf['mode'];
1454
		}
1455

    
1456
		if ($dhcpv6ifconf['ramode'] == "disabled") {
1457
			continue;
1458
		}
1459

    
1460
		$ifcfgipv6 = get_interface_ipv6($dhcpv6if);
1461
		if (!is_ipaddrv6($ifcfgipv6)) {
1462
			continue;
1463
		}
1464

    
1465
		return true;
1466
	}
1467

    
1468
	/* handle DHCP-PD prefixes and 6RD dynamic interfaces */
1469
	foreach ($Iflist as $if => $ifdescr) {
1470
		if (!isset($config['interfaces'][$if]['track6-interface'])) {
1471
			continue;
1472
		}
1473
		if (!isset($config['interfaces'][$if]['enable'])) {
1474
			continue;
1475
		}
1476

    
1477
		$ifcfgipv6 = get_interface_ipv6($if);
1478
		if (!is_ipaddrv6($ifcfgipv6)) {
1479
			continue;
1480
		}
1481

    
1482
		$ifcfgsnv6 = get_interface_subnetv6($if);
1483
		$subnetv6 = gen_subnetv6($ifcfgipv6, $ifcfgsnv6);
1484

    
1485
		if (!is_ipaddrv6($subnetv6)) {
1486
			continue;
1487
		}
1488

    
1489
		return true;
1490
	}
1491

    
1492
	return false;
1493
}
1494

    
1495
/* Any PPPoE servers enabled? */
1496
function is_pppoe_server_enabled() {
1497
	global $config;
1498

    
1499
	$pppoeenable = false;
1500

    
1501
	if (!is_array($config['pppoes']) || !is_array($config['pppoes']['pppoe'])) {
1502
		return false;
1503
	}
1504

    
1505
	foreach ($config['pppoes']['pppoe'] as $pppoes) {
1506
		if ($pppoes['mode'] == 'server') {
1507
			$pppoeenable = true;
1508
		}
1509
	}
1510

    
1511
	return $pppoeenable;
1512
}
1513

    
1514
/* Optional arg forces hh:mm:ss without days */
1515
function convert_seconds_to_dhms($sec, $showhoursonly = false) {
1516
	if (!is_numericint($sec)) {
1517
		return '-';
1518
	}
1519
	// FIXME: When we move to PHP 7 we can use "intdiv($sec % X, Y)" etc
1520
	list($d, $h, $m, $s) = array(	(int)($showhoursonly ? 0 : $sec/86400),
1521
					(int)(($showhoursonly ? $sec : $sec % 86400)/3600),
1522
					(int)(($sec % 3600)/60),
1523
					$sec % 60
1524
				);
1525
	return ($d > 0 ? $d . 'd ' : '') . sprintf('%02d:%02d:%02d', $h, $m, $s);
1526
}
1527

    
1528
/* Compute the total uptime from the ppp uptime log file in the conf directory */
1529

    
1530
function get_ppp_uptime($port) {
1531
	if (file_exists("/conf/{$port}.log")) {
1532
		$saved_time = file_get_contents("/conf/{$port}.log");
1533
		$uptime_data = explode("\n", $saved_time);
1534
		$sec = 0;
1535
		foreach ($uptime_data as $upt) {
1536
			$sec += substr($upt, 1 + strpos($upt, " "));
1537
		}
1538
		return convert_seconds_to_dhms($sec);
1539
	} else {
1540
		$total_time = gettext("No history data found!");
1541
		return $total_time;
1542
	}
1543
}
1544

    
1545
//returns interface information
1546
function get_interface_info($ifdescr) {
1547
	global $config, $g;
1548

    
1549
	$ifinfo = array();
1550
	if (empty($config['interfaces'][$ifdescr])) {
1551
		return;
1552
	}
1553
	$ifinfo['hwif'] = $config['interfaces'][$ifdescr]['if'];
1554
	$ifinfo['if'] = get_real_interface($ifdescr);
1555

    
1556
	$chkif = $ifinfo['if'];
1557
	$ifinfotmp = pfSense_get_interface_addresses($chkif);
1558
	$ifinfo['status'] = $ifinfotmp['status'];
1559
	if (empty($ifinfo['status'])) {
1560
		$ifinfo['status'] = "down";
1561
	}
1562
	$ifinfo['macaddr'] = $ifinfotmp['macaddr'];
1563
	$ifinfo['mtu'] = $ifinfotmp['mtu'];
1564
	$ifinfo['ipaddr'] = $ifinfotmp['ipaddr'];
1565
	$ifinfo['subnet'] = $ifinfotmp['subnet'];
1566
	$ifinfo['linklocal'] = get_interface_linklocal($ifdescr);
1567
	$ifinfo['ipaddrv6'] = get_interface_ipv6($ifdescr);
1568
	$ifinfo['subnetv6'] = get_interface_subnetv6($ifdescr);
1569
	if (isset($ifinfotmp['link0'])) {
1570
		$link0 = "down";
1571
	}
1572
	$ifinfotmp = pfSense_get_interface_stats($chkif);
1573
	// $ifinfo['inpkts'] = $ifinfotmp['inpkts'];
1574
	// $ifinfo['outpkts'] = $ifinfotmp['outpkts'];
1575
	$ifinfo['inerrs'] = $ifinfotmp['inerrs'];
1576
	$ifinfo['outerrs'] = $ifinfotmp['outerrs'];
1577
	$ifinfo['collisions'] = $ifinfotmp['collisions'];
1578

    
1579
	/* Use pfctl for non wrapping 64 bit counters */
1580
	/* Pass */
1581
	exec("/sbin/pfctl -vvsI -i {$chkif}", $pfctlstats);
1582
	$pf_in4_pass = preg_split("/ +/ ", $pfctlstats[3]);
1583
	$pf_out4_pass = preg_split("/ +/", $pfctlstats[5]);
1584
	$pf_in6_pass = preg_split("/ +/ ", $pfctlstats[7]);
1585
	$pf_out6_pass = preg_split("/ +/", $pfctlstats[9]);
1586
	$in4_pass = $pf_in4_pass[5];
1587
	$out4_pass = $pf_out4_pass[5];
1588
	$in4_pass_packets = $pf_in4_pass[3];
1589
	$out4_pass_packets = $pf_out4_pass[3];
1590
	$in6_pass = $pf_in6_pass[5];
1591
	$out6_pass = $pf_out6_pass[5];
1592
	$in6_pass_packets = $pf_in6_pass[3];
1593
	$out6_pass_packets = $pf_out6_pass[3];
1594
	$ifinfo['inbytespass'] = $in4_pass + $in6_pass;
1595
	$ifinfo['outbytespass'] = $out4_pass + $out6_pass;
1596
	$ifinfo['inpktspass'] = $in4_pass_packets + $in6_pass_packets;
1597
	$ifinfo['outpktspass'] = $out4_pass_packets + $out6_pass_packets;
1598

    
1599
	/* Block */
1600
	$pf_in4_block = preg_split("/ +/", $pfctlstats[4]);
1601
	$pf_out4_block = preg_split("/ +/", $pfctlstats[6]);
1602
	$pf_in6_block = preg_split("/ +/", $pfctlstats[8]);
1603
	$pf_out6_block = preg_split("/ +/", $pfctlstats[10]);
1604
	$in4_block = $pf_in4_block[5];
1605
	$out4_block = $pf_out4_block[5];
1606
	$in4_block_packets = $pf_in4_block[3];
1607
	$out4_block_packets = $pf_out4_block[3];
1608
	$in6_block = $pf_in6_block[5];
1609
	$out6_block = $pf_out6_block[5];
1610
	$in6_block_packets = $pf_in6_block[3];
1611
	$out6_block_packets = $pf_out6_block[3];
1612
	$ifinfo['inbytesblock'] = $in4_block + $in6_block;
1613
	$ifinfo['outbytesblock'] = $out4_block + $out6_block;
1614
	$ifinfo['inpktsblock'] = $in4_block_packets + $in6_block_packets;
1615
	$ifinfo['outpktsblock'] = $out4_block_packets + $out6_block_packets;
1616

    
1617
	$ifinfo['inbytes'] = $in4_pass + $in6_pass;
1618
	$ifinfo['outbytes'] = $out4_pass + $out6_pass;
1619
	$ifinfo['inpkts'] = $in4_pass_packets + $in6_pass_packets;
1620
	$ifinfo['outpkts'] = $out4_pass_packets + $out6_pass_packets;
1621

    
1622
	$ifconfiginfo = "";
1623
	$link_type = $config['interfaces'][$ifdescr]['ipaddr'];
1624
	switch ($link_type) {
1625
		/* DHCP? -> see if dhclient is up */
1626
		case "dhcp":
1627
			/* see if dhclient is up */
1628
			if (find_dhclient_process($ifinfo['if']) != 0) {
1629
				$ifinfo['dhcplink'] = "up";
1630
			} else {
1631
				$ifinfo['dhcplink'] = "down";
1632
			}
1633

    
1634
			break;
1635
		/* PPPoE/PPTP/L2TP interface? -> get status from virtual interface */
1636
		case "pppoe":
1637
		case "pptp":
1638
		case "l2tp":
1639
			if ($ifinfo['status'] == "up" && !isset($link0)) {
1640
				/* get PPPoE link status for dial on demand */
1641
				$ifinfo["{$link_type}link"] = "up";
1642
			} else {
1643
				$ifinfo["{$link_type}link"] = "down";
1644
			}
1645

    
1646
			break;
1647
		/* PPP interface? -> get uptime for this session and cumulative uptime from the persistent log file in conf */
1648
		case "ppp":
1649
			if ($ifinfo['status'] == "up") {
1650
				$ifinfo['ppplink'] = "up";
1651
			} else {
1652
				$ifinfo['ppplink'] = "down" ;
1653
			}
1654

    
1655
			if (empty($ifinfo['status'])) {
1656
				$ifinfo['status'] = "down";
1657
			}
1658

    
1659
			if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
1660
				foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
1661
					if ($config['interfaces'][$ifdescr]['if'] == $ppp['if']) {
1662
						break;
1663
					}
1664
				}
1665
			}
1666
			$dev = $ppp['ports'];
1667
			if ($config['interfaces'][$ifdescr]['if'] != $ppp['if'] || empty($dev)) {
1668
				break;
1669
			}
1670
			if (!file_exists($dev)) {
1671
				$ifinfo['nodevice'] = 1;
1672
				$ifinfo['pppinfo'] = $dev . " " . gettext("device not present! Is the modem attached to the system?");
1673
			}
1674

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

    
1710
	if (file_exists("{$g['varrun_path']}/{$link_type}_{$ifdescr}.pid")) {
1711
		$sec = trim(`/usr/local/sbin/ppp-uptime.sh {$ifinfo['if']}`);
1712
		$ifinfo['ppp_uptime'] = convert_seconds_to_dhms($sec);
1713
	}
1714

    
1715
	if ($ifinfo['status'] == "up") {
1716
		/* try to determine media with ifconfig */
1717
		unset($ifconfiginfo);
1718
		exec("/sbin/ifconfig " . $ifinfo['if'], $ifconfiginfo);
1719
		$wifconfiginfo = array();
1720
		if (is_interface_wireless($ifdescr)) {
1721
			exec("/sbin/ifconfig {$ifinfo['if']} list sta", $wifconfiginfo);
1722
			array_shift($wifconfiginfo);
1723
		}
1724
		$matches = "";
1725
		foreach ($ifconfiginfo as $ici) {
1726

    
1727
			/* don't list media/speed for wireless cards, as it always
1728
			   displays 2 Mbps even though clients can connect at 11 Mbps */
1729
			if (preg_match("/media: .*? \((.*?)\)/", $ici, $matches)) {
1730
				$ifinfo['media'] = $matches[1];
1731
			} else if (preg_match("/media: Ethernet (.*)/", $ici, $matches)) {
1732
				$ifinfo['media'] = $matches[1];
1733
			} else if (preg_match("/media: IEEE 802.11 Wireless Ethernet (.*)/", $ici, $matches)) {
1734
				$ifinfo['media'] = $matches[1];
1735
			}
1736

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

    
1782
	$bridge = "";
1783
	$bridge = link_interface_to_bridge($ifdescr);
1784
	if ($bridge) {
1785
		$bridge_text = `/sbin/ifconfig {$bridge}`;
1786
		if (stristr($bridge_text, "blocking") <> false) {
1787
			$ifinfo['bridge'] = "<b><font color='red'>" . gettext("blocking") . "</font></b> - " . gettext("check for ethernet loops");
1788
			$ifinfo['bridgeint'] = $bridge;
1789
		} else if (stristr($bridge_text, "learning") <> false) {
1790
			$ifinfo['bridge'] = gettext("learning");
1791
			$ifinfo['bridgeint'] = $bridge;
1792
		} else if (stristr($bridge_text, "forwarding") <> false) {
1793
			$ifinfo['bridge'] = gettext("forwarding");
1794
			$ifinfo['bridgeint'] = $bridge;
1795
		}
1796
	}
1797

    
1798
	return $ifinfo;
1799
}
1800

    
1801
//returns cpu speed of processor. Good for determining capabilities of machine
1802
function get_cpu_speed() {
1803
	return get_single_sysctl("hw.clockrate");
1804
}
1805

    
1806
function get_uptime_sec() {
1807
	$boottime = "";
1808
	$matches = "";
1809
	$boottime = get_single_sysctl("kern.boottime");
1810
	preg_match("/sec = (\d+)/", $boottime, $matches);
1811
	$boottime = $matches[1];
1812
	if (intval($boottime) == 0) {
1813
		return 0;
1814
	}
1815

    
1816
	$uptime = time() - $boottime;
1817
	return $uptime;
1818
}
1819

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

    
1853
function is_fqdn($fqdn) {
1854
	$hostname = false;
1855
	if (preg_match("/[-A-Z0-9\.]+\.[-A-Z0-9\.]+/i", $fqdn)) {
1856
		$hostname = true;
1857
	}
1858
	if (preg_match("/\.\./", $fqdn)) {
1859
		$hostname = false;
1860
	}
1861
	if (preg_match("/^\./i", $fqdn)) {
1862
		$hostname = false;
1863
	}
1864
	if (preg_match("/\//i", $fqdn)) {
1865
		$hostname = false;
1866
	}
1867
	return($hostname);
1868
}
1869

    
1870
function pfsense_default_state_size() {
1871
	/* get system memory amount */
1872
	$memory = get_memory();
1873
	$physmem = $memory[0];
1874
	/* Be cautious and only allocate 10% of system memory to the state table */
1875
	$max_states = (int) ($physmem/10)*1000;
1876
	return $max_states;
1877
}
1878

    
1879
function pfsense_default_tables_size() {
1880
	$current = `pfctl -sm | grep ^tables | awk '{print $4};'`;
1881
	return $current;
1882
}
1883

    
1884
function pfsense_default_table_entries_size() {
1885
	$current = `pfctl -sm | grep table-entries | awk '{print $4};'`;
1886
	return (trim($current));
1887
}
1888

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

    
1925
	if (trim($oldcontents) != trim($contents)) {
1926
		if ($g['debug']) {
1927
			log_error(sprintf(gettext('DNSCACHE: Found old IP %1$s and new IP %2$s'), $oldcontents, $contents));
1928
		}
1929
		return ($oldcontents);
1930
	} else {
1931
		return false;
1932
	}
1933
}
1934

    
1935
/*
1936
 * load_crypto() - Load crypto modules if enabled in config.
1937
 */
1938
function load_crypto() {
1939
	global $config, $g;
1940
	$crypto_modules = array('glxsb', 'aesni');
1941

    
1942
	if (!in_array($config['system']['crypto_hardware'], $crypto_modules)) {
1943
		return false;
1944
	}
1945

    
1946
	if (!empty($config['system']['crypto_hardware']) && !is_module_loaded($config['system']['crypto_hardware'])) {
1947
		log_error(sprintf(gettext("Loading %s cryptographic accelerator module."), $config['system']['crypto_hardware']));
1948
		mwexec("/sbin/kldload {$config['system']['crypto_hardware']}");
1949
	}
1950
}
1951

    
1952
/*
1953
 * load_thermal_hardware() - Load temperature monitor kernel module
1954
 */
1955
function load_thermal_hardware() {
1956
	global $config, $g;
1957
	$thermal_hardware_modules = array('coretemp', 'amdtemp');
1958

    
1959
	if (!in_array($config['system']['thermal_hardware'], $thermal_hardware_modules)) {
1960
		return false;
1961
	}
1962

    
1963
	if (!empty($config['system']['thermal_hardware']) && !is_module_loaded($config['system']['thermal_hardware'])) {
1964
		log_error(sprintf(gettext("Loading %s thermal monitor module."), $config['system']['thermal_hardware']));
1965
		mwexec("/sbin/kldload {$config['system']['thermal_hardware']}");
1966
	}
1967
}
1968

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

    
1981
	if ($rc != 0 || !isset($output[0])) {
1982
		return false;
1983
	}
1984

    
1985
	foreach ($virtualenvs as $virtualenv) {
1986
		if (stripos($output[0], $virtualenv) !== false) {
1987
			return true;
1988
		}
1989
	}
1990

    
1991
	return false;
1992
}
1993

    
1994
function get_freebsd_version() {
1995
	$version = explode(".", php_uname("r"));
1996
	return $version[0];
1997
}
1998

    
1999
function download_file($url, $destination, $verify_ssl = true, $connect_timeout = 5, $timeout = 0) {
2000
	global $config, $g;
2001

    
2002
	$fp = fopen($destination, "wb");
2003

    
2004
	if (!$fp) {
2005
		return false;
2006
	}
2007

    
2008
	$ch = curl_init();
2009
	curl_setopt($ch, CURLOPT_URL, $url);
2010
	curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, $verify_ssl);
2011
	curl_setopt($ch, CURLOPT_FILE, $fp);
2012
	curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $connect_timeout);
2013
	curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
2014
	curl_setopt($ch, CURLOPT_HEADER, false);
2015
	curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
2016
	if (!isset($config['system']['do_not_send_uniqueid'])) {
2017
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version'] . ':' . system_get_uniqueid());
2018
	} else {
2019
		curl_setopt($ch, CURLOPT_USERAGENT, $g['product_name'] . '/' . $g['product_version']);
2020
	}
2021

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

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

    
2046
function download_file_with_progress_bar($url, $destination, $verify_ssl = true, $readbody = 'read_body', $connect_timeout = 5, $timeout = 0) {
2047
	global $config, $g;
2048
	global $ch, $fout, $file_size, $downloaded, $config, $first_progress_update;
2049
	$file_size = 1;
2050
	$downloaded = 1;
2051
	$first_progress_update = TRUE;
2052
	/* open destination file */
2053
	$fout = fopen($destination, "wb");
2054

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

    
2077
	if (!empty($config['system']['proxyurl'])) {
2078
		curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']);
2079
		if (!empty($config['system']['proxyport'])) {
2080
			curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']);
2081
		}
2082
		if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) {
2083
			@curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE);
2084
			curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}");
2085
		}
2086
	}
2087

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

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

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

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

    
2185
/*
2186
 *   update_status: update top textarea dynamically.
2187
 */
2188
function update_status($status) {
2189
	global $pkg_interface;
2190

    
2191
	if ($pkg_interface == "console") {
2192
		print ("{$status}");
2193
	}
2194

    
2195
	/* ensure that contents are written out */
2196
	ob_flush();
2197
}
2198

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

    
2221
/* 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. */
2222
if (!function_exists("split")) {
2223
	function split($separator, $haystack, $limit = null) {
2224
		log_error("deprecated split() call with separator '{$separator}'");
2225
		return preg_split($separator, $haystack, $limit);
2226
	}
2227
}
2228

    
2229
function update_alias_name($new_alias_name, $orig_alias_name) {
2230
	if (!$orig_alias_name) {
2231
		return;
2232
	}
2233

    
2234
	// Firewall rules
2235
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2236
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2237
	update_alias_names_upon_change(array('filter', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2238
	update_alias_names_upon_change(array('filter', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2239
	// NAT Rules
2240
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2241
	update_alias_names_upon_change(array('nat', 'rule'), array('source', 'port'), $new_alias_name, $orig_alias_name);
2242
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2243
	update_alias_names_upon_change(array('nat', 'rule'), array('destination', 'port'), $new_alias_name, $orig_alias_name);
2244
	update_alias_names_upon_change(array('nat', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2245
	update_alias_names_upon_change(array('nat', 'rule'), array('local-port'), $new_alias_name, $orig_alias_name);
2246
	// NAT 1:1 Rules
2247
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('external'), $new_alias_name, $orig_alias_name);
2248
	//update_alias_names_upon_change(array('nat', 'onetoone'), array('source', 'address'), $new_alias_name, $orig_alias_name);
2249
	update_alias_names_upon_change(array('nat', 'onetoone'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2250
	// NAT Outbound Rules
2251
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('source', 'network'), $new_alias_name, $orig_alias_name);
2252
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('sourceport'), $new_alias_name, $orig_alias_name);
2253
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('destination', 'address'), $new_alias_name, $orig_alias_name);
2254
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('dstport'), $new_alias_name, $orig_alias_name);
2255
	update_alias_names_upon_change(array('nat', 'outbound', 'rule'), array('target'), $new_alias_name, $orig_alias_name);
2256
	// Alias in an alias
2257
	update_alias_names_upon_change(array('aliases', 'alias'), array('address'), $new_alias_name, $orig_alias_name);
2258
}
2259

    
2260
function update_alias_names_upon_change($section, $field, $new_alias_name, $origname) {
2261
	global $g, $config, $pconfig, $debug;
2262
	if (!$origname) {
2263
		return;
2264
	}
2265

    
2266
	$sectionref = &$config;
2267
	foreach ($section as $sectionname) {
2268
		if (is_array($sectionref) && isset($sectionref[$sectionname])) {
2269
			$sectionref = &$sectionref[$sectionname];
2270
		} else {
2271
			return;
2272
		}
2273
	}
2274

    
2275
	if ($debug) {
2276
		$fd = fopen("{$g['tmp_path']}/print_r", "a");
2277
		fwrite($fd, print_r($pconfig, true));
2278
	}
2279

    
2280
	if (is_array($sectionref)) {
2281
		foreach ($sectionref as $itemkey => $item) {
2282
			if ($debug) {
2283
				fwrite($fd, "$itemkey\n");
2284
			}
2285

    
2286
			$fieldfound = true;
2287
			$fieldref = &$sectionref[$itemkey];
2288
			foreach ($field as $fieldname) {
2289
				if (is_array($fieldref) && isset($fieldref[$fieldname])) {
2290
					$fieldref = &$fieldref[$fieldname];
2291
				} else {
2292
					$fieldfound = false;
2293
					break;
2294
				}
2295
			}
2296
			if ($fieldfound && $fieldref == $origname) {
2297
				if ($debug) {
2298
					fwrite($fd, "Setting old alias value $origname to $new_alias_name\n");
2299
				}
2300
				$fieldref = $new_alias_name;
2301
			}
2302
		}
2303
	}
2304

    
2305
	if ($debug) {
2306
		fclose($fd);
2307
	}
2308

    
2309
}
2310

    
2311
function parse_aliases_file($filename, $type = "url", $max_items = -1, $kflc = false) {
2312
	/*
2313
	 * $filename = file to process for example blocklist like DROP:  http://www.spamhaus.org/drop/drop.txt
2314
	 * $type = if set to 'url' then subnets and ips will be returned,
2315
	 *         if set to 'url_ports' port-ranges and ports will be returned
2316
	 * $max_items = sets the maximum amount of valid items to load, -1 the default defines there is no limit.
2317
	 *
2318
	 * RETURNS an array of ip subnets and ip's or ports and port-ranges, returns NULL upon a error conditions (file not found)
2319
	 */
2320

    
2321
	if (!file_exists($filename)) {
2322
		log_error(sprintf(gettext("Could not process non-existent file from alias: %s"), $filename));
2323
		return null;
2324
	}
2325

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

    
2368
function update_alias_url_data() {
2369
	global $config, $g;
2370

    
2371
	$updated = false;
2372

    
2373
	/* item is a url type */
2374
	$lockkey = lock('aliasurl');
2375
	if (is_array($config['aliases']['alias'])) {
2376
		foreach ($config['aliases']['alias'] as $x => $alias) {
2377
			if (empty($alias['aliasurl'])) {
2378
				continue;
2379
			}
2380

    
2381
			$address = null;
2382
			foreach ($alias['aliasurl'] as $alias_url) {
2383
				/* fetch down and add in */
2384
				$temp_filename = tempnam("{$g['tmp_path']}/", "alias_import");
2385
				unlink($temp_filename);
2386
				$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2387
				mkdir($temp_filename);
2388
				if (!download_file($alias_url, $temp_filename . "/aliases", $verify_ssl)) {
2389
					log_error(sprintf(gettext("Failed to download alias %s"), $alias_url));
2390
					continue;
2391
				}
2392

    
2393
				/* if the item is tar gzipped then extract */
2394
				if (stripos($alias_url, '.tgz')) {
2395
					if (!process_alias_tgz($temp_filename)) {
2396
						continue;
2397
					}
2398
				}
2399
				if (file_exists("{$temp_filename}/aliases")) {
2400
					$address = parse_aliases_file("{$temp_filename}/aliases", $alias['type'], 5000);
2401
					mwexec("/bin/rm -rf {$temp_filename}");
2402
				}
2403
			}
2404
			if ($address != null) {
2405
				$config['aliases']['alias'][$x]['address'] = implode(" ", $address);
2406
				$updated = true;
2407
			}
2408
		}
2409
	}
2410
	unlock($lockkey);
2411

    
2412
	/* Report status to callers as well */
2413
	return $updated;
2414
}
2415

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

    
2446
	return true;
2447
}
2448

    
2449
function version_compare_dates($a, $b) {
2450
	$a_time = strtotime($a);
2451
	$b_time = strtotime($b);
2452

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

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

    
2537
		// First try to compare the numeric parts of the version string.
2538
		$v = version_compare_numeric($cur_num, $rem_num);
2539

    
2540
		// If the numeric parts are the same, compare the string parts.
2541
		if ($v == 0) {
2542
			return version_compare_string($cur_str, $rem_str);
2543
		}
2544
	}
2545
	return $v;
2546
}
2547
function process_alias_urltable($name, $type, $url, $freq, $forceupdate=false, $validateonly=false) {
2548
	global $g, $config;
2549

    
2550
	$urltable_prefix = "/var/db/aliastables/";
2551
	$urltable_filename = $urltable_prefix . $name . ".txt";
2552
	$tmp_urltable_filename = $urltable_filename . ".tmp";
2553

    
2554
	// Make the aliases directory if it doesn't exist
2555
	if (!file_exists($urltable_prefix)) {
2556
		mkdir($urltable_prefix);
2557
	} elseif (!is_dir($urltable_prefix)) {
2558
		unlink($urltable_prefix);
2559
		mkdir($urltable_prefix);
2560
	}
2561

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

    
2567
		// Try to fetch the URL supplied
2568
		conf_mount_rw();
2569
		unlink_if_exists($tmp_urltable_filename);
2570
		$verify_ssl = isset($config['system']['checkaliasesurlcert']);
2571
		if (download_file($url, $tmp_urltable_filename, $verify_ssl)) {
2572
			// Convert lines that begin with '$' or ';' to comments '#' instead of deleting them.
2573
			mwexec("/usr/bin/sed -i \"\" -E 's/^[[:space:]]*($|#|;)/#/g; /^#/!s/\;.*//g;' ". escapeshellarg($tmp_urltable_filename));
2574

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

    
2577
			$parsed_contents = parse_aliases_file($tmp_urltable_filename, $type, "-1", true);
2578
			if ($type == "urltable_ports") {
2579
				$parsed_contents = group_ports($parsed_contents, true);
2580
			}
2581
			if (is_array($parsed_contents)) {
2582
				file_put_contents($urltable_filename, implode("\n", $parsed_contents));
2583
			} else {
2584
				touch($urltable_filename);
2585
			}
2586

    
2587
			/* 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. */
2588
			if (($g['platform'] == $g['product_name']) && !isset($config['system']['use_mfs_tmpvar'])) {
2589
				unlink_if_exists("{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz");
2590
			} else {
2591
				/* Update the RAM disk store with the new/updated table file. */
2592
				mwexec("cd / && /usr/bin/tar -czf \"{$g['cf_conf_path']}/RAM_Disk_Store{$urltable_filename}.tgz\" -C / \"{$urltable_filename}\"");
2593
			}
2594
			unlink_if_exists($tmp_urltable_filename);
2595
		} else {
2596
			if (!$validateonly) {
2597
				touch($urltable_filename);
2598
			}
2599
			conf_mount_ro();
2600
			return false;
2601
		}
2602
		conf_mount_ro();
2603
		return true;
2604
	} else {
2605
		// File exists, and it doesn't need to be updated.
2606
		return -1;
2607
	}
2608
}
2609
function get_real_slice_from_glabel($label) {
2610
	$label = escapeshellarg($label);
2611
	return trim(`/sbin/glabel list | /usr/bin/grep -B2 ufs/{$label} | /usr/bin/head -n 1 | /usr/bin/cut -f3 -d' '`);
2612
}
2613
function nanobsd_get_boot_slice() {
2614
	return trim(`/sbin/mount | /usr/bin/grep pfsense | /usr/bin/cut -d'/' -f4 | /usr/bin/cut -d' ' -f1`);
2615
}
2616
function nanobsd_get_boot_drive() {
2617
	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`);
2618
}
2619
function nanobsd_get_active_slice() {
2620
	$boot_drive = nanobsd_get_boot_drive();
2621
	$active = trim(`gpart show $boot_drive | grep '\[active\]' | awk '{print $3;}'`);
2622

    
2623
	return "{$boot_drive}s{$active}";
2624
}
2625
function nanobsd_get_size() {
2626
	return strtoupper(file_get_contents("/etc/nanosize.txt"));
2627
}
2628
function nanobsd_switch_boot_slice() {
2629
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2630
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2631
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2632
	nanobsd_detect_slice_info();
2633

    
2634
	if ($BOOTFLASH == $ACTIVE_SLICE) {
2635
		$slice = $TOFLASH;
2636
	} else {
2637
		$slice = $BOOTFLASH;
2638
	}
2639

    
2640
	for ($i = 0; $i < ob_get_level(); $i++) {
2641
		ob_end_flush();
2642
	}
2643
	ob_implicit_flush(1);
2644
	if (strstr($slice, "s2")) {
2645
		$ASLICE = "2";
2646
		$AOLDSLICE = "1";
2647
		$AGLABEL_SLICE = "pfsense1";
2648
		$AUFS_ID = "1";
2649
		$AOLD_UFS_ID = "0";
2650
	} else {
2651
		$ASLICE = "1";
2652
		$AOLDSLICE = "2";
2653
		$AGLABEL_SLICE = "pfsense0";
2654
		$AUFS_ID = "0";
2655
		$AOLD_UFS_ID = "1";
2656
	}
2657
	$ATOFLASH = "{$BOOT_DRIVE}s{$ASLICE}";
2658
	$ACOMPLETE_PATH = "{$BOOT_DRIVE}s{$ASLICE}a";
2659
	$ABOOTFLASH = "{$BOOT_DRIVE}s{$AOLDSLICE}";
2660
	conf_mount_rw();
2661
	set_single_sysctl("kern.geom.debugflags", "16");
2662
	exec("/sbin/gpart set -a active -i {$ASLICE} {$BOOT_DRIVE}");
2663
	exec("/usr/sbin/boot0cfg -s {$ASLICE} -v /dev/{$BOOT_DRIVE}");
2664
	// We can't update these if they are mounted now.
2665
	if ($BOOTFLASH != $slice) {
2666
		exec("/sbin/tunefs -L ${AGLABEL_SLICE} /dev/$ACOMPLETE_PATH");
2667
		nanobsd_update_fstab($AGLABEL_SLICE, $ACOMPLETE_PATH, $AOLD_UFS_ID, $AUFS_ID);
2668
	}
2669
	set_single_sysctl("kern.geom.debugflags", "0");
2670
	conf_mount_ro();
2671
}
2672
function nanobsd_clone_slice() {
2673
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2674
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2675
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2676
	nanobsd_detect_slice_info();
2677

    
2678
	for ($i = 0; $i < ob_get_level(); $i++) {
2679
		ob_end_flush();
2680
	}
2681
	ob_implicit_flush(1);
2682
	set_single_sysctl("kern.geom.debugflags", "16");
2683
	exec("/bin/dd if=/dev/zero of=/dev/{$TOFLASH} bs=1m count=1");
2684
	exec("/bin/dd if=/dev/{$BOOTFLASH} of=/dev/{$TOFLASH} bs=64k");
2685
	exec("/sbin/tunefs -L {$GLABEL_SLICE} /dev/{$COMPLETE_PATH}");
2686
	$status = nanobsd_update_fstab($GLABEL_SLICE, $COMPLETE_PATH, $OLD_UFS_ID, $UFS_ID);
2687
	set_single_sysctl("kern.geom.debugflags", "0");
2688
	if ($status) {
2689
		return false;
2690
	} else {
2691
		return true;
2692
	}
2693
}
2694
function nanobsd_update_fstab($gslice, $complete_path, $oldufs, $newufs) {
2695
	$tmppath = "/tmp/{$gslice}";
2696
	$fstabpath = "/tmp/{$gslice}/etc/fstab";
2697

    
2698
	mkdir($tmppath);
2699
	exec("/sbin/fsck_ufs -y /dev/{$complete_path}");
2700
	exec("/sbin/mount /dev/ufs/{$gslice} {$tmppath}");
2701
	copy("/etc/fstab", $fstabpath);
2702

    
2703
	if (!file_exists($fstabpath)) {
2704
		$fstab = <<<EOF
2705
/dev/ufs/{$gslice} / ufs ro,noatime 1 1
2706
/dev/ufs/cf /cf ufs ro,noatime 1 1
2707
EOF;
2708
		if (file_put_contents($fstabpath, $fstab)) {
2709
			$status = true;
2710
		} else {
2711
			$status = false;
2712
		}
2713
	} else {
2714
		$status = exec("/usr/bin/sed -i \"\" \"s/pfsense{$oldufs}/pfsense{$newufs}/g\" {$fstabpath}");
2715
	}
2716
	exec("/sbin/umount {$tmppath}");
2717
	rmdir($tmppath);
2718

    
2719
	return $status;
2720
}
2721
function nanobsd_detect_slice_info() {
2722
	global $SLICE, $OLDSLICE, $TOFLASH, $COMPLETE_PATH, $COMPLETE_BOOT_PATH;
2723
	global $GLABEL_SLICE, $UFS_ID, $OLD_UFS_ID, $BOOTFLASH;
2724
	global $BOOT_DEVICE, $REAL_BOOT_DEVICE, $BOOT_DRIVE, $ACTIVE_SLICE;
2725

    
2726
	$BOOT_DEVICE=nanobsd_get_boot_slice();
2727
	$REAL_BOOT_DEVICE=get_real_slice_from_glabel($BOOT_DEVICE);
2728
	$BOOT_DRIVE=nanobsd_get_boot_drive();
2729
	$ACTIVE_SLICE=nanobsd_get_active_slice();
2730

    
2731
	// Detect which slice is active and set information.
2732
	if (strstr($REAL_BOOT_DEVICE, "s1")) {
2733
		$SLICE = "2";
2734
		$OLDSLICE = "1";
2735
		$GLABEL_SLICE = "pfsense1";
2736
		$UFS_ID = "1";
2737
		$OLD_UFS_ID = "0";
2738

    
2739
	} else {
2740
		$SLICE = "1";
2741
		$OLDSLICE = "2";
2742
		$GLABEL_SLICE = "pfsense0";
2743
		$UFS_ID = "0";
2744
		$OLD_UFS_ID = "1";
2745
	}
2746
	$TOFLASH = "{$BOOT_DRIVE}s{$SLICE}";
2747
	$COMPLETE_PATH = "{$BOOT_DRIVE}s{$SLICE}a";
2748
	$COMPLETE_BOOT_PATH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2749
	$BOOTFLASH = "{$BOOT_DRIVE}s{$OLDSLICE}";
2750
}
2751

    
2752
function nanobsd_friendly_slice_name($slicename) {
2753
	global $g;
2754
	return strtolower(str_ireplace('pfsense', $g['product_name'], $slicename));
2755
}
2756

    
2757
function get_include_contents($filename) {
2758
	if (is_file($filename)) {
2759
		ob_start();
2760
		include $filename;
2761
		$contents = ob_get_contents();
2762
		ob_end_clean();
2763
		return $contents;
2764
	}
2765
	return false;
2766
}
2767

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

    
2880
function get_country_name($country_code) {
2881
	if ($country_code != "ALL" && strlen($country_code) != 2) {
2882
		return "";
2883
	}
2884

    
2885
	$country_names_xml = "/usr/local/share/mobile-broadband-provider-info/iso_3166-1_list_en.xml";
2886
	$country_names_contents = file_get_contents($country_names_xml);
2887
	$country_names = xml2array($country_names_contents);
2888

    
2889
	if ($country_code == "ALL") {
2890
		$country_list = array();
2891
		foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2892
			$country_list[] = array(
2893
				"code" => $country['ISO_3166-1_Alpha-2_Code_element'],
2894
				"name" => ucwords(strtolower($country['ISO_3166-1_Country_name'])));
2895
		}
2896
		return $country_list;
2897
	}
2898

    
2899
	foreach ($country_names['ISO_3166-1_List_en']['ISO_3166-1_Entry'] as $country) {
2900
		if ($country['ISO_3166-1_Alpha-2_Code_element'] == strtoupper($country_code)) {
2901
			return ucwords(strtolower($country['ISO_3166-1_Country_name']));
2902
		}
2903
	}
2904
	return "";
2905
}
2906

    
2907
/* sort by interface only, retain the original order of rules that apply to
2908
   the same interface */
2909
function filter_rules_sort() {
2910
	global $config;
2911

    
2912
	/* mark each rule with the sequence number (to retain the order while sorting) */
2913
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2914
		$config['filter']['rule'][$i]['seq'] = $i;
2915
	}
2916

    
2917
	usort($config['filter']['rule'], "filter_rules_compare");
2918

    
2919
	/* strip the sequence numbers again */
2920
	for ($i = 0; isset($config['filter']['rule'][$i]); $i++) {
2921
		unset($config['filter']['rule'][$i]['seq']);
2922
	}
2923
}
2924
function filter_rules_compare($a, $b) {
2925
	if (isset($a['floating']) && isset($b['floating'])) {
2926
		return $a['seq'] - $b['seq'];
2927
	} else if (isset($a['floating'])) {
2928
		return -1;
2929
	} else if (isset($b['floating'])) {
2930
		return 1;
2931
	} else if ($a['interface'] == $b['interface']) {
2932
		return $a['seq'] - $b['seq'];
2933
	} else {
2934
		return compare_interface_friendly_names($a['interface'], $b['interface']);
2935
	}
2936
}
2937

    
2938
function generate_ipv6_from_mac($mac) {
2939
	$elements = explode(":", $mac);
2940
	if (count($elements) <> 6) {
2941
		return false;
2942
	}
2943

    
2944
	$i = 0;
2945
	$ipv6 = "fe80::";
2946
	foreach ($elements as $byte) {
2947
		if ($i == 0) {
2948
			$hexadecimal = substr($byte, 1, 2);
2949
			$bitmap = base_convert($hexadecimal, 16, 2);
2950
			$bitmap = str_pad($bitmap, 4, "0", STR_PAD_LEFT);
2951
			$bitmap = substr($bitmap, 0, 2) ."1". substr($bitmap, 3, 4);
2952
			$byte = substr($byte, 0, 1) . base_convert($bitmap, 2, 16);
2953
		}
2954
		$ipv6 .= $byte;
2955
		if ($i == 1) {
2956
			$ipv6 .= ":";
2957
		}
2958
		if ($i == 3) {
2959
			$ipv6 .= ":";
2960
		}
2961
		if ($i == 2) {
2962
			$ipv6 .= "ff:fe";
2963
		}
2964

    
2965
		$i++;
2966
	}
2967
	return $ipv6;
2968
}
2969

    
2970
/****f* pfsense-utils/load_mac_manufacturer_table
2971
 * NAME
2972
 *   load_mac_manufacturer_table
2973
 * INPUTS
2974
 *   none
2975
 * RESULT
2976
 *   returns associative array with MAC-Manufacturer pairs
2977
 ******/
2978
function load_mac_manufacturer_table() {
2979
	/* load MAC-Manufacture data from the file */
2980
	$macs = false;
2981
	if (file_exists("/usr/local/share/nmap/nmap-mac-prefixes")) {
2982
		$macs=file("/usr/local/share/nmap/nmap-mac-prefixes");
2983
	}
2984
	if ($macs) {
2985
		foreach ($macs as $line) {
2986
			if (preg_match('/([0-9A-Fa-f]{6}) (.*)$/', $line, $matches)) {
2987
				/* store values like this $mac_man['000C29']='VMware' */
2988
				$mac_man["$matches[1]"] = $matches[2];
2989
			}
2990
		}
2991
		return $mac_man;
2992
	} else {
2993
		return -1;
2994
	}
2995

    
2996
}
2997

    
2998
/****f* pfsense-utils/is_ipaddr_configured
2999
 * NAME
3000
 *   is_ipaddr_configured
3001
 * INPUTS
3002
 *   IP Address to check.
3003
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
3004
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
3005
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
3006
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
3007
 *     If check_subnets is true and cidrprefix is specified,
3008
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
3009
 * RESULT
3010
 *   returns true if the IP Address is configured and present on this device or overlaps a configured subnet.
3011
*/
3012
function is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
3013
	if (count(where_is_ipaddr_configured($ipaddr, $ignore_if, $check_localip, $check_subnets, $cidrprefix))) {
3014
		return true;
3015
	}
3016
	return false;
3017
}
3018

    
3019
/****f* pfsense-utils/where_is_ipaddr_configured
3020
 * NAME
3021
 *   where_is_ipaddr_configured
3022
 * INPUTS
3023
 *   IP Address to check.
3024
 *   If ignore_if is a VIP (not carp), vip array index is passed after string _virtualip
3025
 *   check_localip - if true then also check for matches with PPTP and L2TP addresses
3026
 *   check_subnets - if true then check if the given ipaddr is contained anywhere in the subnet of any other configured IP address
3027
 *   cidrprefix - the CIDR prefix (16, 20, 24, 64...) of ipaddr.
3028
 *     If check_subnets is true and cidrprefix is specified,
3029
 *     then check if the ipaddr/cidrprefix subnet overlaps the subnet of any other configured IP address
3030
 * RESULT
3031
 *   Returns an array of the interfaces 'if' plus IP address or subnet 'ip_or_subnet' that match or overlap the IP address to check.
3032
 *   If there are no matches then an empty array is returned.
3033
*/
3034
function where_is_ipaddr_configured($ipaddr, $ignore_if = "", $check_localip = false, $check_subnets = false, $cidrprefix = "") {
3035
	global $config;
3036

    
3037
	$where_configured = array();
3038

    
3039
	$pos = strpos($ignore_if, '_virtualip');
3040
	if ($pos !== false) {
3041
		$ignore_vip_id = substr($ignore_if, $pos+10);
3042
		$ignore_vip_if = substr($ignore_if, 0, $pos);
3043
	} else {
3044
		$ignore_vip_id = -1;
3045
		$ignore_vip_if = $ignore_if;
3046
	}
3047

    
3048
	$isipv6 = is_ipaddrv6($ipaddr);
3049

    
3050
	if ($isipv6) {
3051
		$ipaddr = text_to_compressed_ip6($ipaddr);
3052
	}
3053

    
3054
	if ($check_subnets) {
3055
		$cidrprefix = intval($cidrprefix);
3056
		if ($isipv6) {
3057
			if (($cidrprefix < 1) || ($cidrprefix > 128)) {
3058
				$cidrprefix = 128;
3059
			}
3060
		} else {
3061
			if (($cidrprefix < 1) || ($cidrprefix > 32)) {
3062
				$cidrprefix = 32;
3063
			}
3064
		}
3065
		$iflist = get_configured_interface_list();
3066
		foreach ($iflist as $if => $ifname) {
3067
			if ($ignore_if == $if) {
3068
				continue;
3069
			}
3070

    
3071
			if ($isipv6) {
3072
				$if_ipv6 = get_interface_ipv6($if);
3073
				$if_snbitsv6 = get_interface_subnetv6($if);
3074
				if ($if_ipv6 && $if_snbitsv6 && check_subnetsv6_overlap($ipaddr, $cidrprefix, $if_ipv6, $if_snbitsv6)) {
3075
					$where_entry = array();
3076
					$where_entry['if'] = $if;
3077
					$where_entry['ip_or_subnet'] = get_interface_ipv6($if) . "/" . get_interface_subnetv6($if);
3078
					$where_configured[] = $where_entry;
3079
				}
3080
			} else {
3081
				$if_ipv4 = get_interface_ip($if);
3082
				$if_snbitsv4 = get_interface_subnet($if);
3083
				if ($if_ipv4 && $if_snbitsv4 && check_subnets_overlap($ipaddr, $cidrprefix, $if_ipv4, $if_snbitsv4)) {
3084
					$where_entry = array();
3085
					$where_entry['if'] = $if;
3086
					$where_entry['ip_or_subnet'] = get_interface_ip($if) . "/" . get_interface_subnet($if);
3087
					$where_configured[] = $where_entry;
3088
				}
3089
			}
3090
		}
3091
	} else {
3092
		if ($isipv6) {
3093
			$interface_list_ips = get_configured_ipv6_addresses();
3094
		} else {
3095
			$interface_list_ips = get_configured_ip_addresses();
3096
		}
3097

    
3098
		foreach ($interface_list_ips as $if => $ilips) {
3099
			if ($ignore_if == $if) {
3100
				continue;
3101
			}
3102
			if (strcasecmp($ipaddr, $ilips) == 0) {
3103
				$where_entry = array();
3104
				$where_entry['if'] = $if;
3105
				$where_entry['ip_or_subnet'] = $ilips;
3106
				$where_configured[] = $where_entry;
3107
			}
3108
		}
3109
	}
3110

    
3111
	if ($check_localip) {
3112
		if (!is_array($config['l2tp']) && !empty($config['l2tp']['localip']) && (strcasecmp($ipaddr, text_to_compressed_ip6($config['l2tp']['localip'])) == 0)) {
3113
			$where_entry = array();
3114
			$where_entry['if'] = 'l2tp';
3115
			$where_entry['ip_or_subnet'] = $config['l2tp']['localip'];
3116
			$where_configured[] = $where_entry;
3117
		}
3118
	}
3119

    
3120
	return $where_configured;
3121
}
3122

    
3123
/****f* pfsense-utils/pfSense_handle_custom_code
3124
 * NAME
3125
 *   pfSense_handle_custom_code
3126
 * INPUTS
3127
 *   directory name to process
3128
 * RESULT
3129
 *   globs the directory and includes the files
3130
 */
3131
function pfSense_handle_custom_code($src_dir) {
3132
	// Allow extending of the nat edit page and include custom input validation
3133
	if (is_dir("$src_dir")) {
3134
		$cf = glob($src_dir . "/*.inc");
3135
		foreach ($cf as $nf) {
3136
			if ($nf == "." || $nf == "..") {
3137
				continue;
3138
			}
3139
			// Include the extra handler
3140
			include_once("$nf");
3141
		}
3142
	}
3143
}
3144

    
3145
function set_language() {
3146
	global $config, $g;
3147

    
3148
	if (!empty($config['system']['language'])) {
3149
		$lang = $config['system']['language'];
3150
	} elseif (!empty($g['language'])) {
3151
		$lang = $g['language'];
3152
	}
3153
	$lang .= ".UTF-8";
3154

    
3155
	putenv("LANG={$lang}");
3156
	setlocale(LC_ALL, $lang);
3157
	textdomain("pfSense");
3158
	bindtextdomain("pfSense", "/usr/local/share/locale");
3159
	bind_textdomain_codeset("pfSense", $lang);
3160
}
3161

    
3162
function get_locale_list() {
3163
	$locales = array(
3164
		"en_US" => gettext("English"),
3165
		"pt_BR" => gettext("Portuguese (Brazil)"),
3166
		"tr" => gettext("Turkish"),
3167
	);
3168
	asort($locales);
3169
	return $locales;
3170
}
3171

    
3172
function return_hex_ipv4($ipv4) {
3173
	if (!is_ipaddrv4($ipv4)) {
3174
		return(false);
3175
	}
3176

    
3177
	/* we need the hex form of the interface IPv4 address */
3178
	$ip4arr = explode(".", $ipv4);
3179
	return (sprintf("%02x%02x%02x%02x", $ip4arr[0], $ip4arr[1], $ip4arr[2], $ip4arr[3]));
3180
}
3181

    
3182
function convert_ipv6_to_128bit($ipv6) {
3183
	if (!is_ipaddrv6($ipv6)) {
3184
		return(false);
3185
	}
3186

    
3187
	$ip6arr = array();
3188
	$ip6prefix = Net_IPv6::uncompress($ipv6);
3189
	$ip6arr = explode(":", $ip6prefix);
3190
	/* binary presentation of the prefix for all 128 bits. */
3191
	$ip6prefixbin = "";
3192
	foreach ($ip6arr as $element) {
3193
		$ip6prefixbin .= sprintf("%016b", hexdec($element));
3194
	}
3195
	return($ip6prefixbin);
3196
}
3197

    
3198
function convert_128bit_to_ipv6($ip6bin) {
3199
	if (strlen($ip6bin) <> 128) {
3200
		return(false);
3201
	}
3202

    
3203
	$ip6arr = array();
3204
	$ip6binarr = array();
3205
	$ip6binarr = str_split($ip6bin, 16);
3206
	foreach ($ip6binarr as $binpart) {
3207
		$ip6arr[] = dechex(bindec($binpart));
3208
	}
3209
	$ip6addr = text_to_compressed_ip6(implode(":", $ip6arr));
3210

    
3211
	return($ip6addr);
3212
}
3213

    
3214

    
3215
/* Returns the calculated bit length of the prefix delegation from the WAN interface */
3216
/* DHCP-PD is variable, calculate from the prefix-len on the WAN interface */
3217
/* 6rd is variable, calculate from 64 - (v6 prefixlen - (32 - v4 prefixlen)) */
3218
/* 6to4 is 16 bits, e.g. 65535 */
3219
function calculate_ipv6_delegation_length($if) {
3220
	global $config;
3221

    
3222
	if (!is_array($config['interfaces'][$if])) {
3223
		return false;
3224
	}
3225

    
3226
	switch ($config['interfaces'][$if]['ipaddrv6']) {
3227
		case "6to4":
3228
			$pdlen = 16;
3229
			break;
3230
		case "6rd":
3231
			$rd6cfg = $config['interfaces'][$if];
3232
			$rd6plen = explode("/", $rd6cfg['prefix-6rd']);
3233
			$pdlen = (64 - ($rd6plen[1] + (32 - $rd6cfg['prefix-6rd-v4plen'])));
3234
			break;
3235
		case "dhcp6":
3236
			$dhcp6cfg = $config['interfaces'][$if];
3237
			$pdlen = $dhcp6cfg['dhcp6-ia-pd-len'];
3238
			break;
3239
		default:
3240
			$pdlen = 0;
3241
			break;
3242
	}
3243
	return($pdlen);
3244
}
3245

    
3246
function merge_ipv6_delegated_prefix($prefix, $suffix, $len = 64) {
3247
	$prefix = Net_IPv6::uncompress($prefix, true);
3248
	$suffix = Net_IPv6::uncompress($suffix, true);
3249

    
3250
	/*
3251
	 * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
3252
	 *                ^^^^ ^
3253
	 *                |||| \-> 64
3254
	 *                |||\---> 63, 62, 61, 60
3255
	 *                ||\----> 56
3256
	 *                |\-----> 52
3257
	 *                \------> 48
3258
	 */
3259

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

    
3291
	return text_to_compressed_ip6(substr($prefix, 0, $prefix_len) .
3292
	    substr($suffix, $prefix_len));
3293
}
3294

    
3295
function dhcpv6_pd_str_help($pdlen) {
3296
	$result = '';
3297

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

    
3330
	return $result;
3331
}
3332

    
3333
function huawei_rssi_to_string($rssi) {
3334
	$dbm = array();
3335
	$i = 0;
3336
	$dbstart = -113;
3337
	while ($i < 32) {
3338
		$dbm[$i] = $dbstart + ($i * 2);
3339
		$i++;
3340
	}
3341
	$percent = round(($rssi / 31) * 100);
3342
	$string = "rssi:{$rssi} level:{$dbm[$rssi]}dBm percent:{$percent}%";
3343
	return $string;
3344
}
3345

    
3346
function huawei_mode_to_string($mode, $submode) {
3347
	$modes[0] = gettext("None");
3348
	$modes[1] = "AMPS";
3349
	$modes[2] = "CDMA";
3350
	$modes[3] = "GSM/GPRS";
3351
	$modes[4] = "HDR";
3352
	$modes[5] = "WCDMA";
3353
	$modes[6] = "GPS";
3354

    
3355
	$submodes[0] = gettext("No Service");
3356
	$submodes[1] = "GSM";
3357
	$submodes[2] = "GPRS";
3358
	$submodes[3] = "EDGE";
3359
	$submodes[4] = "WCDMA";
3360
	$submodes[5] = "HSDPA";
3361
	$submodes[6] = "HSUPA";
3362
	$submodes[7] = "HSDPA+HSUPA";
3363
	$submodes[8] = "TD-SCDMA";
3364
	$submodes[9] = "HSPA+";
3365
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3366
	return $string;
3367
}
3368

    
3369
function huawei_service_to_string($state) {
3370
	$modes[0] = gettext("No Service");
3371
	$modes[1] = gettext("Restricted Service");
3372
	$modes[2] = gettext("Valid Service");
3373
	$modes[3] = gettext("Restricted Regional Service");
3374
	$modes[4] = gettext("Powersaving Service");
3375
	$string = $modes[$state];
3376
	return $string;
3377
}
3378

    
3379
function huawei_simstate_to_string($state) {
3380
	$modes[0] = gettext("Invalid SIM/locked State");
3381
	$modes[1] = gettext("Valid SIM State");
3382
	$modes[2] = gettext("Invalid SIM CS State");
3383
	$modes[3] = gettext("Invalid SIM PS State");
3384
	$modes[4] = gettext("Invalid SIM CS/PS State");
3385
	$modes[255] = gettext("Missing SIM State");
3386
	$string = $modes[$state];
3387
	return $string;
3388
}
3389

    
3390
function zte_rssi_to_string($rssi) {
3391
	return huawei_rssi_to_string($rssi);
3392
}
3393

    
3394
function zte_mode_to_string($mode, $submode) {
3395
	$modes[0] = gettext("No Service");
3396
	$modes[1] = gettext("Limited Service");
3397
	$modes[2] = "GPRS";
3398
	$modes[3] = "GSM";
3399
	$modes[4] = "UMTS";
3400
	$modes[5] = "EDGE";
3401
	$modes[6] = "HSDPA";
3402

    
3403
	$submodes[0] = "CS_ONLY";
3404
	$submodes[1] = "PS_ONLY";
3405
	$submodes[2] = "CS_PS";
3406
	$submodes[3] = "CAMPED";
3407
	$string = "{$modes[$mode]}, {$submodes[$submode]} " . gettext("Mode");
3408
	return $string;
3409
}
3410

    
3411
function zte_service_to_string($service) {
3412
	$modes[0] = gettext("Initializing Service");
3413
	$modes[1] = gettext("Network Lock error Service");
3414
	$modes[2] = gettext("Network Locked Service");
3415
	$modes[3] = gettext("Unlocked or correct MCC/MNC Service");
3416
	$string = $modes[$service];
3417
	return $string;
3418
}
3419

    
3420
function zte_simstate_to_string($state) {
3421
	$modes[0] = gettext("No action State");
3422
	$modes[1] = gettext("Network lock State");
3423
	$modes[2] = gettext("(U)SIM card lock State");
3424
	$modes[3] = gettext("Network Lock and (U)SIM card Lock State");
3425
	$string = $modes[$state];
3426
	return $string;
3427
}
3428

    
3429
function get_configured_pppoe_server_interfaces() {
3430
	global $config;
3431
	$iflist = array();
3432
	if (is_array($config['pppoes']['pppoe'])) {
3433
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
3434
			if ($pppoe['mode'] == "server") {
3435
				$int = "poes". $pppoe['pppoeid'];
3436
				$iflist[$int] = strtoupper($int);
3437
			}
3438
		}
3439
	}
3440
	return $iflist;
3441
}
3442

    
3443
function get_pppoes_child_interfaces($ifpattern) {
3444
	$if_arr = array();
3445
	if ($ifpattern == "") {
3446
		return;
3447
	}
3448

    
3449
	exec("/sbin/ifconfig", $out, $ret);
3450
	foreach ($out as $line) {
3451
		if (preg_match("/^({$ifpattern}[0-9]+):/i", $line, $match)) {
3452
			$if_arr[] = $match[1];
3453
		}
3454
	}
3455
	return $if_arr;
3456

    
3457
}
3458

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

    
3499
function restore_aliastables() {
3500
	global $g, $config;
3501

    
3502
	$dbpath = "{$g['vardb_path']}/aliastables/";
3503

    
3504
	/* restore the alias tables, if we have them */
3505
	$files = glob("{$g['cf_conf_path']}/RAM_Disk_Store{$dbpath}*.tgz");
3506
	if (count($files)) {
3507
		echo "Restoring alias tables...";
3508
		foreach ($files as $file) {
3509
			if (file_exists($file)) {
3510
				$aliastablesrestore = "";
3511
				$aliastablesreturn = "";
3512
				exec("cd /;LANG=C /usr/bin/tar -xzf {$file} 2>&1", $aliastablesrestore, $aliastablesreturn);
3513
				$aliastablesrestore = implode(" ", $aliastablesrestore);
3514
				if ($aliastablesreturn <> 0) {
3515
					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"));
3516
				} else {
3517
					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"));
3518
				}
3519
			}
3520
			/* 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. */
3521
			if (($g['platform'] == $g['product_name']) && !isset($config['system']['use_mfs_tmpvar'])) {
3522
				unlink_if_exists("{$file}");
3523
			}
3524
		}
3525
		echo "done.\n";
3526
		return true;
3527
	}
3528
	return false;
3529
}
3530

    
3531
// Convert IPv6 addresses to lower case
3532
function addrtolower($ip) {
3533
	if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) === false) {
3534
		return(strtolower($ip));
3535
	} else {
3536
		return($ip);
3537
	}
3538
}
3539
?>
(43-43/69)