Project

General

Profile

Download (220 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * interfaces.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2004-2013 BSD Perimeter
7
 * Copyright (c) 2013-2016 Electric Sheep Fencing
8
 * Copyright (c) 2014-2021 Rubicon Communications, LLC (Netgate)
9
 * All rights reserved.
10
 *
11
 * originally based on m0n0wall (http://m0n0.ch/wall)
12
 * Copyright (c) 2004 Manuel Kasper <mk@neon1.net>.
13
 * All rights reserved.
14
 *
15
 * Licensed under the Apache License, Version 2.0 (the "License");
16
 * you may not use this file except in compliance with the License.
17
 * You may obtain a copy of the License at
18
 *
19
 * http://www.apache.org/licenses/LICENSE-2.0
20
 *
21
 * Unless required by applicable law or agreed to in writing, software
22
 * distributed under the License is distributed on an "AS IS" BASIS,
23
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
24
 * See the License for the specific language governing permissions and
25
 * limitations under the License.
26
 */
27

    
28
/* include all configuration functions */
29
require_once("globals.inc");
30
require_once("util.inc");
31
require_once("gwlb.inc");
32
require_once("ipsec.inc");
33

    
34
function interfaces_bring_up($interface) {
35
	if (!$interface) {
36
		log_error(gettext("interfaces_bring_up() was called but no variable defined."));
37
		log_error("Backtrace: " . debug_backtrace());
38
		return;
39
	}
40
	pfSense_interface_flags($interface, IFF_UP);
41
}
42

    
43
/*
44
 * Validate comma-separated list of IPv4 addresses
45
 */
46
function validate_ipv4_list($value) {
47
	$value = trim($value);
48

    
49
	if (empty($value)) {
50
		return false;
51
	}
52

    
53
	$list = explode(',', $value);
54

    
55
	foreach ($list as $ip) {
56
		if (!is_ipaddrv4($ip)) {
57
			return false;
58
		}
59
	}
60

    
61
	return true;
62
}
63

    
64
/*
65
 * Return the interface array
66
 */
67
function get_interface_arr($flush = false) {
68
	global $interface_arr_cache;
69

    
70
	/* If the cache doesn't exist, build it */
71
	if (!isset($interface_arr_cache) or $flush) {
72
		$interface_arr_cache = pfSense_interface_listget();
73
	}
74

    
75
	return $interface_arr_cache;
76
}
77

    
78
/*
79
 * does_interface_exist($interface): return true or false if a interface is
80
 * detected.
81
 */
82
function does_interface_exist($interface, $flush = false) {
83
	global $config;
84

    
85
	if (!$interface) {
86
		return false;
87
	}
88

    
89
	$ints = get_interface_arr($flush);
90
	if (in_array($interface, $ints)) {
91
		return true;
92
	} else {
93
		return false;
94
	}
95
}
96

    
97
/*
98
 * does_vip_exist($vip): return true or false if a vip is
99
 * configured.
100
 */
101
function does_vip_exist($vip) {
102
	global $config;
103

    
104
	if (!$vip) {
105
		return false;
106
	}
107

    
108

    
109
	switch ($vip['mode']) {
110
		case "carp":
111
		case "ipalias":
112
			/* XXX: Make proper checks? */
113
			$realif = get_real_interface($vip['interface']);
114
			if (!does_interface_exist($realif)) {
115
				return false;
116
			}
117
			break;
118
		case "proxyarp":
119
			/* XXX: Implement this */
120
		default:
121
			return false;
122
	}
123

    
124
	$ifacedata = pfSense_getall_interface_addresses($realif);
125

    
126
	if (is_subnetv6("{$vip['subnet']}/{$vip['subnet_bits']}")) {
127
		$comparevip = text_to_compressed_ip6("{$vip['subnet']}/{$vip['subnet_bits']}");
128
	} else {
129
		$comparevip = "{$vip['subnet']}/{$vip['subnet_bits']}";
130
	}
131

    
132
	foreach ($ifacedata as $vipips) {
133
		if ($vipips == $comparevip) {
134
			return true;
135
		}
136
	}
137

    
138
	return false;
139
}
140

    
141
function interface_netgraph_needed($interface = "wan") {
142
	global $config;
143

    
144
	$found = false;
145
	if (!empty($config['l2tp']) &&
146
	    $config['l2tp']['mode'] == "server") {
147
		$found = true;
148
	}
149
	if ($found == false && is_array($config['pppoes']['pppoe'])) {
150
		foreach ($config['pppoes']['pppoe'] as $pppoe) {
151
			if ($pppoe['mode'] != "server") {
152
				continue;
153
			}
154
			if ($pppoe['interface'] == $interface) {
155
				$found = true;
156
				break;
157
			}
158
		}
159
	}
160
	if ($found == false) {
161
		$found = interface_isppp_type($interface);
162
	}
163

    
164
	if ($found == false) {
165
		$realif = get_real_interface($interface);
166
		init_config_arr(array('ppps', 'ppp'));
167
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
168
			$ports = explode(',', $ppp['ports']);
169
			foreach ($ports as $pid => $port) {
170
				$port = get_real_interface($port);
171
				if ($realif == $port) {
172
					$found = true;
173
					break;
174
				}
175
				/* Find the parent interfaces of the vlans in the MLPPP configs
176
				* there should be only one element in the array here
177
				* -- this could be better . . . */
178
				$parent_if = get_parent_interface($port);
179
				if ($realif == $parent_if[0]) {
180
					$found = true;
181
					break;
182
				}
183
			}
184
		}
185
	}
186

    
187
	if ($found == false) {
188
		$realif = get_real_interface($interface);
189
		pfSense_ngctl_detach("{$realif}:", $realif);
190
	}
191
	/* NOTE: We make sure for this on interface_ppps_configure()
192
	 *	no need to do it here again.
193
	 *	else
194
	 *		pfSense_ngctl_attach(".", $realif);
195
	 */
196
}
197

    
198
function interfaces_loopback_configure() {
199
	global $g;
200

    
201
	if (platform_booting()) {
202
		echo gettext("Configuring loopback interface...");
203
	}
204
	pfSense_interface_setaddress("lo0", "127.0.0.1");
205
	interfaces_bring_up("lo0");
206
	if (platform_booting()) {
207
		echo gettext("done.") . "\n";
208
	}
209
	return 0;
210
}
211

    
212
function vlan_valid_tag($tag = NULL) {
213

    
214
	if ($tag == NULL || empty($tag) ||
215
	    !is_numericint($tag) || intval($tag) < 1 || intval($tag) > 4094) {
216
		return (false);
217
	}
218
	return (true);
219
}
220

    
221
function qinq_inuse($qinq = NULL, $inqtag = NULL) {
222
        global $config;
223

    
224
	if ($qinq == NULL || $inqtag == NULL ||
225
	    !is_array($qinq) || !vlan_valid_tag($inqtag)) {
226
		return (false);
227
	}
228

    
229
        $iflist = get_configured_interface_list(true);
230
        foreach ($iflist as $if) {
231
                if ($config['interfaces'][$if]['if'] == qinq_interface($qinq, $inqtag)) {
232
                        return (true);
233
                }
234
        }
235

    
236
        return (false);
237
}
238

    
239
function qinq_interface($qinq = NULL, $inqtag = NULL) {
240

    
241
	if ($qinq == NULL || $inqtag == NULL || !is_array($qinq) ||
242
	    !isset($qinq['if']) || !isset($qinq['tag']) ||
243
	    !vlan_valid_tag($qinq['tag']) || !vlan_valid_tag($inqtag)) {
244
		return (NULL);
245
	}
246
	return ("{$qinq['if']}.{$qinq['tag']}.{$inqtag}");
247
}
248

    
249
function interface_is_qinq($if = NULL) {
250
	global $config;
251

    
252
	if ($if == NULL || empty($if) || !is_array($config['qinqs']['qinqentry'])) {
253
		return (NULL);
254
	}
255

    
256
	/* Check basic format. */
257
	list($qinqif, $vlantag, $inqtag) = explode(".", $if);
258
	if (empty($qinqif) || empty($vlantag) || empty($inqtag) ||
259
	    !vlan_valid_tag($vlantag) || !vlan_valid_tag($inqtag)) {
260
		return (NULL);
261
	}
262

    
263
	foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
264
		if ("{$qinqif}.{$vlantag}" != $qinq['vlanif']) {
265
			continue;
266
		}
267
		if (empty($qinq['members'])) {
268
			continue;
269
		}
270
		foreach (explode(" ", $qinq['members']) as $tag) {
271
			if ($if == qinq_interface($qinq, $tag)) {
272
				return ($qinq);
273
			}
274
		}
275
	}
276

    
277
	return (NULL);
278
}
279

    
280
function vlan_inuse($vlan) {
281
	global $config;
282

    
283
	if ($vlan == NULL || !is_array($vlan)) {
284
		return (false);
285
	}
286

    
287
	$iflist = get_configured_interface_list(true);
288
	foreach ($iflist as $if) {
289
		if ($config['interfaces'][$if]['if'] == $vlan['vlanif']) {
290
			return (true);
291
		}
292
	}
293

    
294
	return (false);
295
}
296

    
297
function interface_is_vlan($if = NULL) {
298
	global $config;
299

    
300
	if ($if == NULL || empty($if) || is_array($if)) {
301
		return (NULL);
302
	}
303

    
304
	/* Check basic format. */
305
	list($vlanif, $vlantag) = explode(".", $if);
306
	if (empty($vlanif) || empty($vlantag) || !vlan_valid_tag($vlantag)) {
307
		return (NULL);
308
	}
309

    
310
	/* Find the VLAN interface. */
311
	if (isset($config['vlans']['vlan']) && is_array($config['vlans']['vlan'])) {
312
		foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
313
			if ($if == $vlan['vlanif']) {
314
				return ($vlan);
315
			}
316
		}
317
	}
318

    
319
	/* Check for the first level tag in QinQ interfaces. */
320
	if (isset($config['qinqs']['qinqentry']) && is_array($config['qinqs']['qinqentry'])) {
321
		foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
322
			if ($if == $qinq['vlanif']) {
323
				return ($qinq);
324
			}
325
		}
326
	}
327

    
328
	return (NULL);
329
}
330

    
331
function vlan_interface($vlan = NULL) {
332
	if ($vlan == NULL || !is_array($vlan) || !isset($vlan['if']) ||
333
	    !isset($vlan['tag']) || !vlan_valid_tag($vlan['tag'])) {
334
		return (NULL);
335
	}
336
	return ("{$vlan['if']}.{$vlan['tag']}");
337
}
338

    
339
function interface_set_macaddr($interface, $mac_addr) {
340
	if (empty($mac_addr) || !is_macaddr($mac_addr)) {
341
		return;
342
	}
343

    
344
	$current_mac = get_interface_mac($interface);
345

    
346
	/*
347
	 * Don't try to reapply the MAC if it's already applied.
348
	 * When ifconfig link is used, it cycles the interface down/up, which
349
	 * triggers the interface config again, which attempts to apply the
350
	 * MAC again, which cycles the link again...
351
	 */
352
	if ($mac_addr != $current_mac) {
353
		mwexec("/sbin/ifconfig " . escapeshellarg($interface) .
354
		    " link " . escapeshellarg($mac_addr));
355
	}
356
}
357

    
358
function interface_is_parent($if, $parent_check) {
359

    
360
	$parent_array = get_parent_interface($if);
361
	if (count($parent_array) > 1) {
362
		$parent = $parent_array;
363
	} else {
364
		$parent = $parent_array[0];
365
	}
366
	if (is_array($parent)) {
367
		foreach ($parent as $parentif) {
368
			if (strcasecmp($parent_check, $parentif) == 0) {
369
				return (TRUE);
370
			}
371
		}
372
	} else {
373
		$realif = get_real_interface($parent);
374
		if (strcasecmp($parent_check, $realif) == 0) {
375
			return (TRUE);
376
		}
377
	}
378
	return (FALSE);
379
}
380

    
381
function interface_has_clones($if) {
382
	global $config;
383

    
384
	/* Check LAGGs. */
385
	if (isset($config['laggs']) && isset($config['laggs']['lagg']) &&
386
	    is_array($config['laggs']['lagg'])) {
387
		foreach ($config['laggs']['lagg'] as $lagg) {
388
			if (interface_is_parent($lagg['laggif'], $if)) {
389
				return (TRUE);
390
			}
391
		}
392
	}
393
	/* Check VLANs. */
394
	if (isset($config['vlans']) && isset($config['vlans']['vlan']) &&
395
	    is_array($config['vlans']['vlan'])) {
396
		foreach ($config['vlans']['vlan'] as $vlan) {
397
			if (interface_is_parent($vlan['if'], $if)) {
398
				return (TRUE);
399
			}
400
		}
401
	}
402
	/* Check bridges. */
403
	if (isset($config['bridges']) && isset($config['bridges']['bridged']) &&
404
	    is_array($config['bridges']['bridged'])) {
405
		foreach ($config['bridges']['bridged'] as $bridge) {
406
			$members = explode(',', $bridge['members']);
407
			foreach ($members as $member) {
408
				if (interface_is_parent($member, $if)) {
409
					return (TRUE);
410
				}
411
			}
412
		}
413
	}
414

    
415
	return (FALSE);
416
}
417

    
418
function interfaces_vlan_configure($parentif = "") {
419
	global $config, $g;
420
	$dhcp6c_list = array();
421

    
422
	if (platform_booting()) {
423
		echo gettext("Configuring VLAN interfaces...");
424
	}
425
	if (is_array($config['vlans']['vlan']) &&
426
	    count($config['vlans']['vlan'])) {
427
		foreach ($config['vlans']['vlan'] as $vlan) {
428
			if (empty($vlan['vlanif'])) {
429
				$vlan['vlanif'] = vlan_interface($vlan);
430
			}
431
			if (!empty($parentif) && ($parentif != $vlan['if'])) {
432
				continue;
433
			}
434
			/* configure dhcp6 enabled VLAN interfaces later
435
			 * see https://redmine.pfsense.org/issues/3965 */
436
			$if = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
437
			if (!empty($config['interfaces'][$if]['ipaddrv6']) &&
438
			    $config['interfaces'][$if]['ipaddrv6'] == "dhcp6") {
439
				$dhcp6c_list[$if] = $vlan;
440
				continue;
441
			}
442

    
443
			/* XXX: Maybe we should report any errors?! */
444
			interface_vlan_configure($vlan, false);
445
		}
446
		foreach ($dhcp6c_list as $if => $vlan) {
447
			interface_vlan_configure($vlan, false);
448
		}
449
	}
450

    
451
	/* Invalidate cache */
452
	get_interface_arr(true);
453

    
454
	if (platform_booting()) {
455
		echo gettext("done.") . "\n";
456
	}
457
}
458

    
459
function interface_vlan_configure(&$vlan, $flush = true) {
460
	global $config, $g;
461

    
462
	if (!is_array($vlan)) {
463
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
464
		return(NULL);
465
	}
466
	$if = $vlan['if'];
467
	if (empty($if)) {
468
		log_error(gettext("interface_vlan_configure called with if undefined."));
469
		return(NULL);
470
	}
471

    
472
	$vlanif = empty($vlan['vlanif']) ? vlan_interface($vlan) : $vlan['vlanif'];
473
	if ($vlanif == NULL) {
474
		log_error(gettext("vlan_interface called with if undefined var."));
475
		return(NULL);
476
	}
477
	$tag = $vlan['tag'];
478
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
479

    
480
	/* make sure the parent interface is up */
481
	interfaces_bring_up($if);
482
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
483
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
484

    
485
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
486
		pfSense_interface_destroy($vlanif);
487
	}
488

    
489
	$tmpvlanif = pfSense_interface_create2("vlan");
490
	pfSense_interface_rename($tmpvlanif, $vlanif);
491
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
492

    
493
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
494

    
495
	interfaces_bring_up($vlanif);
496

    
497
	/* invalidate interface cache */
498
	if ($flush) {
499
		get_interface_arr(true);
500
	}
501

    
502
	/* configure interface if assigned */
503
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
504
	if ($assignedif) {
505
		if (isset($config['interfaces'][$assignedif]['enable'])) {
506
			interface_configure($assignedif, true);
507
		}
508
	}
509

    
510
	/* XXX: ermal -- for now leave it here at the moment it does not hurt. */
511
	interfaces_bring_up($if);
512

    
513
	if (interface_vlan_mtu_configured($vlanif)) {
514
		set_interface_mtu($vlanif, interface_vlan_mtu_configured($vlanif));
515
	}
516

    
517
	return $vlanif;
518
}
519

    
520
/*
521
 * reconfigure VLAN childs interfaces after MTU changes, see
522
 * https://redmine.pfsense.org/issues/11035
523
 */
524
function interfaces_vlan_configure_mtu($parentif = "") {
525
	global $config;
526

    
527
	init_config_arr(array('ppps', 'ppp'));
528
	if (!is_array($config['vlans']['vlan']) ||
529
	    !count($config['vlans']['vlan'])) {
530
		return;
531
	}
532

    
533
	foreach ($config['vlans']['vlan'] as $vlan) {
534
		if ($parentif != $vlan['if']) {
535
			continue;
536
		}
537
		if (interface_vlan_mtu_configured($vlan['vlanif'])) {
538
		       set_interface_mtu($vlan['vlanif'],
539
			   interface_vlan_mtu_configured($vlan['vlanif']));
540
		}
541
		if (empty($config['ppps']['ppp'])) {
542
			continue;
543
		}
544
		// PPP interfaces must be restarted to adjust MTU changes
545
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
546
			$ports = explode(',', $ppp['ports']);
547
			foreach ($ports as $pid => $port) {
548
				if ($port != $vlan['vlanif']) {
549
					continue;
550
				}
551
				$confif = convert_real_interface_to_friendly_interface_name($ppp['if']);
552
				interface_configure($confif);
553
			}
554
		}
555
	}
556
}
557

    
558
function interface_qinq_configure(&$qinq, $fd = NULL, $flush = true) {
559
	global $config, $g;
560

    
561
	if (!is_array($qinq)) {
562
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
563
		return;
564
	}
565

    
566
	$qinqif = $qinq['if'];
567
	$tag = $qinq['tag'];
568
	if (empty($qinqif)) {
569
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
570
		return;
571
	}
572

    
573
	if (!does_interface_exist($qinqif)) {
574
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
575
		return;
576
	}
577

    
578
	$vlanif = interface_vlan_configure($qinq);
579
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
580
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
581
		return;
582
	}
583

    
584
	if ($fd == NULL) {
585
		$exec = true;
586
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
587
	} else {
588
		$exec = false;
589
	}
590
	/* make sure the parent is converted to ng_vlan(4) and is up */
591
	interfaces_bring_up($qinqif);
592

    
593
	pfSense_ngctl_attach(".", $qinqif);
594
	$ngif = str_replace(".", "_", $vlanif);
595
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
596
		exec("/usr/sbin/ngctl shutdown {$ngif}qinq: > /dev/null 2>&1");
597
		exec("/usr/sbin/ngctl msg {$ngif}qinq: gettable > /dev/null 2>&1", $result);
598
		if (empty($result)) {
599
			fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
600
			fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
601
			fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
602
		}
603
	} else {
604
		fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
605
		fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
606
		fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
607
	}
608

    
609
	/* invalidate interface cache */
610
	if ($flush) {
611
		get_interface_arr(true);
612
	}
613

    
614
	if (interface_is_vlan($qinqif) == NULL) {
615
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
616
	}
617

    
618
	$macaddr = get_interface_mac($qinqif);
619
	if (!empty($qinq['members'])) {
620
		$qinqcmdbuf = "";
621
		$members = explode(" ", $qinq['members']);
622
		foreach ($members as $qtag) {
623
			$qinq2 = array();
624
			$qinq2['tag'] = $qtag;
625
			$qinq2['if'] = $vlanif;
626
			interface_qinq2_configure($qinq2, $qinqcmdbuf, $macaddr,
627
			    false);
628
			unset($qinq2);
629
		}
630
		if (strlen($qinqcmdbuf) > 0) {
631
			fwrite($fd, $qinqcmdbuf);
632
		}
633
	}
634
	if ($exec == true) {
635
		fclose($fd);
636
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd > /dev/null 2>&1");
637
	}
638

    
639
	interfaces_bring_up($qinqif);
640
	if (!empty($qinq['members'])) {
641
		$members = explode(" ", $qinq['members']);
642
		foreach ($members as $qtag) {
643
			interfaces_bring_up(qinq_interface($qinq, $qtag));
644
		}
645
	}
646

    
647
	return $vlanif;
648
}
649

    
650
function interfaces_qinq_configure() {
651
	global $config, $g;
652
	if (platform_booting()) {
653
		echo gettext("Configuring QinQ interfaces...");
654
	}
655
	if (is_array($config['qinqs']['qinqentry']) &&
656
	    count($config['qinqs']['qinqentry'])) {
657
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
658
			/* XXX: Maybe we should report any errors?! */
659
			interface_qinq_configure($qinq, NULL, false);
660
		}
661
	}
662

    
663
	/* Invalidate cache */
664
	get_interface_arr(true);
665

    
666
	if (platform_booting()) {
667
		echo gettext("done.") . "\n";
668
	}
669
}
670

    
671
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr, $flush = true) {
672
	global $config, $g;
673

    
674
	if (!is_array($qinq)) {
675
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
676
		return;
677
	}
678

    
679
	$if = $qinq['if'];
680
	if (empty($if)) {
681
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
682
		return;
683
	}
684
	$tag = $qinq['tag'];
685
	$vlanif = "{$if}.{$tag}";
686
	$ngif = str_replace(".", "_", $if);
687
	if (strlen($vlanif) > IF_NAMESIZE) {
688
		log_error(sprintf(gettext("interface_qinq2_configure interface name too big %s. (max. size: %d).%s"),
689
		    $vlanif, IF_NAMESIZE, "\n"));
690
		return;
691
	}
692

    
693
	exec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1");
694
	$cmdbuf .= "mkpeer {$ngif}qinq: eiface {$ngif}{$tag} ether\n";
695
	$cmdbuf .= "name {$ngif}qinq:{$ngif}{$tag} {$ngif}h{$tag}\n";
696
	$cmdbuf .= "msg {$ngif}qinq: addfilter { vlan={$tag} hook=\"{$ngif}{$tag}\" }\n";
697
	$cmdbuf .= "msg {$ngif}h{$tag}: setifname \"{$vlanif}\"\n";
698
	$cmdbuf .= "msg {$ngif}h{$tag}: set {$macaddr}\n";
699

    
700
	/* invalidate interface cache */
701
	if ($flush) {
702
		get_interface_arr(true);
703
	}
704

    
705
	return $vlanif;
706
}
707

    
708
function interfaces_create_wireless_clones() {
709
	global $config, $g;
710

    
711
	if (platform_booting()) {
712
		echo gettext("Creating wireless clone interfaces...");
713
	}
714

    
715
	$iflist = get_configured_interface_list();
716

    
717
	foreach ($iflist as $if) {
718
		$realif = $config['interfaces'][$if]['if'];
719
		if (!is_interface_wireless($realif)) {
720
			continue;
721
		}
722
		interface_wireless_clone(interface_get_wireless_clone($realif),
723
		    $config['interfaces'][$if]);
724
	}
725

    
726
	if (isset($config['wireless']['clone']) &&
727
	    is_array($config['wireless']['clone']) &&
728
	    count($config['wireless']['clone'])) {
729
		foreach ($config['wireless']['clone'] as $clone) {
730
			if (empty($clone['cloneif'])) {
731
				continue;
732
			}
733
			if (does_interface_exist($clone['cloneif'])) {
734
				continue;
735
			}
736
			/* XXX: Maybe we should report any errors?! */
737
			interface_wireless_clone($clone['cloneif'], $clone);
738
		}
739
	}
740
	if (platform_booting()) {
741
		echo gettext("done.") . "\n";
742
	}
743

    
744
}
745

    
746
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
747
	global $config;
748

    
749
	if (!isset($config['bridges']['bridged']) ||
750
	    !is_array($config['bridges']['bridged']) ||
751
	    !count($config['bridges']['bridged'])) {
752
		return;
753
	}
754

    
755
	$i = 0;
756
	foreach ($config['bridges']['bridged'] as $bridge) {
757
		if (empty($bridge['bridgeif'])) {
758
			$bridge['bridgeif'] = "bridge{$i}";
759
		}
760
		if (!empty($realif) && ($realif != $bridge['bridgeif'])) {
761
			continue;
762
		}
763
		$ifname = false;
764
		foreach ($config['interfaces'] as $intname => $intpar) {
765
			if ($intpar['if'] == $bridge['bridgeif']) {
766
				$ifname = $intname;
767
				break;
768
			}
769
		}
770

    
771
		if ($ifname && ($config['interfaces'][$ifname]['ipaddrv6'] == "track6")) {
772
			if ($checkmember == 1) {
773
				continue;
774
			} else {
775
				$checkmember = 0;
776
			}
777
		} elseif (($checkmember == 2) && !$ifname) {
778
			continue;
779
		}
780

    
781
		/* XXX: Maybe we should report any errors?! */
782
		interface_bridge_configure($bridge, $checkmember, false);
783
		$i++;
784
	}
785

    
786
	/* Invalidate cache */
787
	get_interface_arr(true);
788
}
789

    
790
function interface_bridge_configure(&$bridge, $checkmember = 0, $flush = true) {
791
	global $config, $g;
792

    
793
	if (!is_array($bridge)) {
794
		return;
795
	}
796

    
797
	if (empty($bridge['members'])) {
798
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
799
		return;
800
	}
801

    
802
	$members = explode(',', $bridge['members']);
803
	if (!count($members)) {
804
		return;
805
	}
806

    
807
	/* Calculate smaller mtu and enforce it */
808
	$smallermtu = 0;
809
	$foundgif = false;
810
	foreach ($members as $member) {
811
		$realif = get_real_interface($member);
812
		$mtu = get_interface_mtu($realif);
813
		if (substr($realif, 0, 3) == "gif") {
814
			$foundgif = true;
815
			if ($checkmember == 1) {
816
				return;
817
			}
818
			if ($mtu <= 1500) {
819
				continue;
820
			}
821
		}
822
		if ($smallermtu == 0 && !empty($mtu)) {
823
			$smallermtu = $mtu;
824
		} elseif (!empty($mtu) && $mtu < $smallermtu) {
825
			$smallermtu = $mtu;
826
		}
827
	}
828
	if ($foundgif == false && $checkmember == 2) {
829
		return;
830
	}
831

    
832
	/* Just in case anything is not working well */
833
	if ($smallermtu == 0) {
834
		$smallermtu = 1500;
835
	}
836

    
837
	if (!empty($bridge['bridgeif'])) {
838
		pfSense_interface_destroy($bridge['bridgeif']);
839
		pfSense_interface_create2($bridge['bridgeif']);
840
		$bridgeif = escapeshellarg($bridge['bridgeif']);
841
	} else {
842
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
843
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
844
		$bridgeif = pfSense_interface_create2("bridge");
845
		$bridge['bridgeif'] = $bridgeif;
846
	}
847

    
848
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
849
	if ($bridgemtu > $smallermtu) {
850
		$smallermtu = $bridgemtu;
851
	}
852

    
853
	$checklist = get_configured_interface_list();
854

    
855
	/* Add interfaces to bridge */
856
	foreach ($members as $member) {
857
		if (empty($checklist[$member])) {
858
			continue;
859
		}
860
		$realif = get_real_interface($member);
861
		if (!$realif) {
862
			log_error(gettext("realif not defined in interfaces bridge - up"));
863
			continue;
864
		}
865
		/* make sure the parent interface is up */
866
		pfSense_interface_mtu($realif, $smallermtu);
867
		interfaces_bring_up($realif);
868
		enable_hardware_offloading($member);
869
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
870
	}
871

    
872
	if (isset($bridge['enablestp'])) {
873
		interface_bridge_configure_stp($bridge);
874
	}
875

    
876
	interface_bridge_configure_advanced($bridge);
877

    
878
	interface_bridge_configure_ip6linklocal($bridge);
879

    
880
	if ($flush) {
881
		get_interface_arr(true);
882
	}
883

    
884
	if ($bridge['bridgeif']) {
885
		interfaces_bring_up($bridge['bridgeif']);
886
	} else {
887
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
888
	}
889
}
890

    
891
function interface_bridge_configure_stp($bridge) {
892
	if (isset($bridge['enablestp'])) {
893
		$bridgeif = trim($bridge['bridgeif']);
894
		/* configure spanning tree proto */
895
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
896

    
897
		if (!empty($bridge['stp'])) {
898
			$stpifs = explode(',', $bridge['stp']);
899
			foreach ($stpifs as $stpif) {
900
				$realif = get_real_interface($stpif);
901
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
902
			}
903
		}
904
		if (!empty($bridge['maxage'])) {
905
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
906
		}
907
		if (!empty($bridge['fwdelay'])) {
908
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
909
		}
910
		if (!empty($bridge['hellotime'])) {
911
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
912
		}
913
		if (!empty($bridge['priority'])) {
914
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
915
		}
916
		if (!empty($bridge['holdcnt'])) {
917
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
918
		}
919
		if (!empty($bridge['ifpriority'])) {
920
			$pconfig = explode(",", $bridge['ifpriority']);
921
			$ifpriority = array();
922
			foreach ($pconfig as $cfg) {
923
				$embcfg = explode_assoc(":", $cfg);
924
				foreach ($embcfg as $key => $value) {
925
					$ifpriority[$key] = $value;
926
				}
927
			}
928
			foreach ($ifpriority as $key => $value) {
929
				$realif = get_real_interface($key);
930
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
931
			}
932
		}
933
		if (!empty($bridge['ifpathcost'])) {
934
			$pconfig = explode(",", $bridge['ifpathcost']);
935
			$ifpathcost = array();
936
			foreach ($pconfig as $cfg) {
937
				$embcfg = explode_assoc(":", $cfg);
938
				foreach ($embcfg as $key => $value) {
939
					$ifpathcost[$key] = $value;
940
				}
941
			}
942
			foreach ($ifpathcost as $key => $value) {
943
				$realif = get_real_interface($key);
944
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
945
			}
946
		}
947
	}
948
}
949

    
950
function interface_bridge_configure_advanced($bridge) {
951
	$bridgeif = trim($bridge['bridgeif']);
952

    
953
	if ($bridge['maxaddr'] <> "") {
954
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
955
	}
956
	if ($bridge['timeout'] <> "") {
957
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
958
	}
959
	if (!empty($bridge['span'])) {
960
		$spanifs = explode(",", $bridge['span']);
961
		foreach ($spanifs as $spanif) {
962
			$realif = get_real_interface($spanif);
963
			mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
964
		}
965
	}
966
	if (!empty($bridge['edge'])) {
967
		$edgeifs = explode(',', $bridge['edge']);
968
		foreach ($edgeifs as $edgeif) {
969
			$realif = get_real_interface($edgeif);
970
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
971
		}
972
	}
973
	if (!empty($bridge['autoedge'])) {
974
		$edgeifs = explode(',', $bridge['autoedge']);
975
		foreach ($edgeifs as $edgeif) {
976
			$realif = get_real_interface($edgeif);
977
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
978
		}
979
	}
980
	if (!empty($bridge['ptp'])) {
981
		$ptpifs = explode(',', $bridge['ptp']);
982
		foreach ($ptpifs as $ptpif) {
983
			$realif = get_real_interface($ptpif);
984
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
985
		}
986
	}
987
	if (!empty($bridge['autoptp'])) {
988
		$ptpifs = explode(',', $bridge['autoptp']);
989
		foreach ($ptpifs as $ptpif) {
990
			$realif = get_real_interface($ptpif);
991
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
992
		}
993
	}
994
	if (!empty($bridge['static'])) {
995
		$stickyifs = explode(',', $bridge['static']);
996
		foreach ($stickyifs as $stickyif) {
997
			$realif = get_real_interface($stickyif);
998
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
999
		}
1000
	}
1001
	if (!empty($bridge['private'])) {
1002
		$privateifs = explode(',', $bridge['private']);
1003
		foreach ($privateifs as $privateif) {
1004
			$realif = get_real_interface($privateif);
1005
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
1006
		}
1007
	}
1008
}
1009

    
1010
function interface_bridge_configure_ip6linklocal($bridge) {
1011
	$bridgeif = trim($bridge['bridgeif']);
1012

    
1013
	$members = explode(',', $bridge['members']);
1014
	if (!count($members)) {
1015
		return;
1016
	}
1017

    
1018
	$auto_linklocal = isset($bridge['ip6linklocal']);
1019
	$bridgeop = $auto_linklocal ? '' : '-';
1020
	$memberop = $auto_linklocal ? '-' : '';
1021

    
1022
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
1023
	foreach ($members as $member) {
1024
		$realif = get_real_interface($member);
1025
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
1026
	}
1027
}
1028

    
1029
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
1030
	global $config;
1031

    
1032
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
1033
		return;
1034
	}
1035

    
1036
	if ($flagsapplied == false) {
1037
		$mtu = get_interface_mtu($bridgeif);
1038
		$mtum = get_interface_mtu($interface);
1039
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
1040
			pfSense_interface_mtu($interface, $mtu);
1041
		}
1042

    
1043
		hardware_offloading_applyflags($interface);
1044
		interfaces_bring_up($interface);
1045
	}
1046

    
1047
	pfSense_bridge_add_member($bridgeif, $interface);
1048
	if (is_array($config['bridges']['bridged'])) {
1049
		foreach ($config['bridges']['bridged'] as $bridge) {
1050
			if ($bridgeif == $bridge['bridgeif']) {
1051
				interface_bridge_configure_stp($bridge);
1052
				interface_bridge_configure_advanced($bridge);
1053
			}
1054
		}
1055
	}
1056
}
1057

    
1058
function interfaces_lagg_configure($realif = "") {
1059
	global $config, $g;
1060
	if (platform_booting()) {
1061
		echo gettext("Configuring LAGG interfaces...");
1062
	}
1063
	$i = 0;
1064
	if (is_array($config['laggs']['lagg']) &&
1065
	    count($config['laggs']['lagg'])) {
1066
		foreach ($config['laggs']['lagg'] as $lagg) {
1067
			if (empty($lagg['laggif'])) {
1068
				$lagg['laggif'] = "lagg{$i}";
1069
			}
1070
			if (!empty($realif) && $realif != $lagg['laggif']) {
1071
				continue;
1072
			}
1073
			/* XXX: Maybe we should report any errors?! */
1074
			interface_lagg_configure($lagg, false);
1075
			$i++;
1076
		}
1077

    
1078
		/* Invalidate cache */
1079
		get_interface_arr(true);
1080
	}
1081
	if (platform_booting()) {
1082
		echo gettext("done.") . "\n";
1083
	}
1084
}
1085

    
1086
function interface_lagg_configure($lagg, $flush = true) {
1087
	global $config, $g;
1088

    
1089
	if (!is_array($lagg)) {
1090
		return -1;
1091
	}
1092

    
1093
	$members = explode(',', $lagg['members']);
1094
	if (!count($members)) {
1095
		return -1;
1096
	}
1097

    
1098
	if (platform_booting() || !(empty($lagg['laggif']))) {
1099
		pfSense_interface_destroy($lagg['laggif']);
1100
		pfSense_interface_create2($lagg['laggif']);
1101
		$laggif = $lagg['laggif'];
1102
	} else {
1103
		$laggif = pfSense_interface_create2("lagg");
1104
	}
1105

    
1106
	/* Check if MTU was defined for this lagg interface */
1107
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
1108
	if ($lagg_mtu == 0 &&
1109
	    is_array($config['interfaces'])) {
1110
		foreach ($config['interfaces'] as $tmpinterface) {
1111
			if ($tmpinterface['if'] == $lagg['laggif'] &&
1112
			    !empty($tmpinterface['mtu'])) {
1113
				$lagg_mtu = $tmpinterface['mtu'];
1114
				break;
1115
			}
1116
		}
1117
	}
1118

    
1119
	/* Just in case anything is not working well */
1120
	if ($lagg_mtu == 0) {
1121
		$lagg_mtu = 1500;
1122
	}
1123

    
1124
	// put failover master interface on top of list
1125
	if (($lagg['proto'] == 'failover') && isset($lagg['failovermaster']) &&
1126
	    ($lagg['failovermaster'] != 'auto')) {
1127
		unset($members[array_search($lagg['failovermaster'], $members)]);
1128
		$members = array_merge(array($lagg['failovermaster']), $members);
1129
	}
1130

    
1131
	if (($lagg['proto'] == 'lacp') && isset($lagg['lacptimeout']) &&
1132
	    ($lagg['lacptimeout'] != 'slow')) {
1133
		$lacptimeout = 'lacp_fast_timeout';
1134
	} else {
1135
		$lacptimeout = '';
1136
	}
1137

    
1138
	foreach ($members as $member) {
1139
		if (!does_interface_exist($member)) {
1140
			continue;
1141
		}
1142

    
1143
		/* make sure the parent interface is up */
1144
		pfSense_interface_mtu($member, $lagg_mtu);
1145
		interfaces_bring_up($member);
1146
		hardware_offloading_applyflags($member);
1147

    
1148
		// Ensure there are no nulls in these values. It upsets escapeshellarg()
1149
		$laggif = str_replace("\0", "", $laggif);
1150
		$member = str_replace("\0", "", $member);
1151
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
1152
	}
1153

    
1154
	mwexec("/sbin/ifconfig {$laggif} laggproto " . escapeshellarg($lagg['proto']) . " {$lacptimeout}");
1155

    
1156
	if ($flush) {
1157
		get_interface_arr(true);
1158
	}
1159

    
1160
	interfaces_bring_up($laggif);
1161

    
1162
	return $laggif;
1163
}
1164

    
1165
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
1166
function interface_gre_configure(&$gre, $grekey = "", $flush = true) {
1167
	global $config, $g;
1168

    
1169
	if (!is_array($gre)) {
1170
		return -1;
1171
	}
1172

    
1173
	$realif = convert_friendly_interface_to_real_interface_name($gre['if']);
1174
	if (!interface_is_vlan($realif)) {
1175
		$realif = get_real_interface($gre['if']);
1176
	}
1177
	$realifip = get_interface_ip($gre['if']);
1178
	$realifip6 = get_interface_ipv6($gre['if']);
1179

    
1180
	/* make sure the parent interface is up */
1181
	interfaces_bring_up($realif);
1182

    
1183
	if (platform_booting() || !(empty($gre['greif']))) {
1184
		pfSense_interface_destroy($gre['greif']);
1185
		pfSense_interface_create2($gre['greif']);
1186
		$greif = $gre['greif'];
1187
	} else {
1188
		$greif = pfSense_interface_create2("gre");
1189
	}
1190

    
1191
	$tunnel_type = '';
1192
	if ((!empty($gre['tunnel-local-addr'])) || (!empty($gre['tunnel-remote-addr']))) {
1193
		$tunnel_type = 'v4';
1194
	}
1195
	if ((!empty($gre['tunnel-local-addr6'])) || (!empty($gre['tunnel-remote-addr6']))) {
1196
		$tunnel_type .= 'v6';
1197
	}
1198

    
1199
	/* Do not change the order here for more see gre(4) NOTES section. */
1200
	if (is_ipaddrv6($gre['remote-addr'])) {
1201
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
1202
	} else {
1203
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
1204
	}
1205
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1206
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
1207
	}
1208
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1209
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1210
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr6']) . " " . escapeshellarg($gre['tunnel-remote-addr6']) . " prefixlen 128");
1211
	}
1212

    
1213
	$parentif = get_real_interface($gre['if']);
1214
	if ($parentif) {
1215
		interfaces_bring_up($parentif);
1216
	} else {
1217
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gre_configure()"));
1218
	}
1219

    
1220
	if (isset($gre['link1'])) {
1221
		if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1222
			mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1223
		}
1224
		if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1225
			mwexec("/sbin/route -6 add " . escapeshellarg($gre['tunnel-remote-addr6']) . "/" . escapeshellarg($gre['tunnel-remote-net6']) . " " . escapeshellarg($gre['tunnel-local-addr6']));
1226
		}
1227
	}
1228
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1229
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1230
	}
1231
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1232
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr6']);
1233
	}
1234

    
1235
	if ($flush) {
1236
		get_interface_arr(true);
1237
	}
1238

    
1239
	interfaces_bring_up($greif);
1240

    
1241
	return $greif;
1242
}
1243

    
1244
function interface_is_type($if = NULL, $type) {
1245
	global $config;
1246
	switch ($type) {
1247
		case "gre":
1248
			$list = 'gres';
1249
			$entry = 'gre';
1250
			$entif = 'greif';
1251
			break;
1252
		case "gif":
1253
			$list = 'gifs';
1254
			$entry = 'gif';
1255
			$entif = 'gifif';
1256
			break;
1257
		case "lagg":
1258
			$list = 'laggs';
1259
			$entry = 'lagg';
1260
			$entif = 'laggif';
1261
			break;
1262
		default:
1263
			break;
1264
	}
1265

    
1266
	if (!isset($config[$list][$entry]) || !is_array($config[$list][$entry])) {
1267
		return (NULL);
1268
	}
1269

    
1270
	foreach ($config[$list][$entry] as $ent) {
1271
		if ($ent[$entif] == $if) {
1272
			return ($ent);
1273
		}
1274
	}
1275
	return (NULL);
1276
}
1277

    
1278
function is_greipsec($if) {
1279
	global $config;
1280

    
1281
	if (ipsec_enabled() && is_array($config['gres']) &&
1282
	    is_array($config['gres']['gre']) &&
1283
	    is_array($config['ipsec']['phase2'])) {
1284
		foreach ($config['gres']['gre'] as $gre) {
1285
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
1286
				foreach ($config['ipsec']['phase2'] as $ph2ent) {
1287
					if (($ph1ent['ikeid'] == $ph2ent['ikeid']) && ($ph2ent['mode'] == 'transport') &&
1288
					    !isset($ph1ent['disabled']) && !isset($ph2ent['disabled']) &&
1289
					    ($ph1ent['interface'] == $gre['if']) && ($gre['greif'] == $if) &&
1290
					    ($ph1ent['remote-gateway'] == $gre['remote-addr'])) {
1291
						    return true;
1292
					}
1293
				}
1294
			}
1295
		}
1296
	}
1297
	return false;
1298
}
1299

    
1300
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1301
function interface_gif_configure(&$gif, $gifkey = "", $flush = true) {
1302
	global $config, $g;
1303

    
1304
	if (!is_array($gif)) {
1305
		return -1;
1306
	}
1307

    
1308
	$realif = convert_friendly_interface_to_real_interface_name($gif['if']);
1309
	if (!interface_is_vlan($realif)) {
1310
		$realif = get_real_interface($gif['if']);
1311
	}
1312
	$ipaddr = get_interface_ip($gif['if']);
1313

    
1314
	if (is_ipaddrv4($gif['remote-addr'])) {
1315
		if (is_ipaddrv4($ipaddr)) {
1316
			$realifip = $ipaddr;
1317
		} else {
1318
			$realifip = get_interface_ip($gif['if']);
1319
		}
1320
		$realifgw = get_interface_gateway($gif['if']);
1321
	} elseif (is_ipaddrv6($gif['remote-addr'])) {
1322
		if (is_ipaddrv6($ipaddr)) {
1323
			$realifip = $ipaddr;
1324
		} else {
1325
			$realifip = get_interface_ipv6($gif['if']);
1326
		}
1327
		$realifgw = get_interface_gateway_v6($gif['if']);
1328
	}
1329
	/* make sure the parent interface is up */
1330
	$parentif = get_real_interface($gif['if']);
1331
	if ($parentif) {
1332
		interfaces_bring_up($parentif);
1333
	} else {
1334
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gif_configure()"));
1335
	}
1336

    
1337
	if (platform_booting() || !(empty($gif['gifif']))) {
1338
		pfSense_interface_destroy($gif['gifif']);
1339
		pfSense_interface_create2($gif['gifif']);
1340
		$gifif = $gif['gifif'];
1341
	} else {
1342
		$gifif = pfSense_interface_create2("gif");
1343
	}
1344

    
1345
	/* Do not change the order here for more see gif(4) NOTES section. */
1346
	if (is_ipaddrv6($gif['remote-addr'])) {
1347
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1348
	} else {
1349
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1350
	}
1351
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1352
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1353
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1354
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1355
	} else {
1356
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1357
	}
1358
	if (isset($gif['link1'])) {
1359
		pfSense_interface_flags($gifif, IFF_LINK1);
1360
	}
1361
	if (isset($gif['link2'])) {
1362
		pfSense_interface_flags($gifif, IFF_LINK2);
1363
	}
1364
	if ($gifif) {
1365
		interfaces_bring_up($gifif);
1366
		$gifmtu = "";
1367
		$currentgifmtu = get_interface_mtu($gifif);
1368
		foreach ($config['interfaces'] as $tmpinterface) {
1369
			if ($tmpinterface['if'] == $gifif) {
1370
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1371
					$gifmtu = $tmpinterface['mtu'];
1372
				}
1373
			}
1374
		}
1375
		if (is_numericint($gifmtu)) {
1376
			if ($gifmtu != $currentgifmtu) {
1377
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1378
			}
1379
		}
1380
	} else {
1381
		log_error(gettext("could not bring gifif up -- variable not defined"));
1382
	}
1383

    
1384
	if (!platform_booting()) {
1385
		$iflist = get_configured_interface_list();
1386
		foreach ($iflist as $ifname) {
1387
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1388
				if (get_interface_gateway($ifname)) {
1389
					system_routing_configure($ifname);
1390
					break;
1391
				}
1392
				if (get_interface_gateway_v6($ifname)) {
1393
					system_routing_configure($ifname);
1394
					break;
1395
				}
1396
			}
1397
		}
1398
	}
1399

    
1400

    
1401
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1402
		file_put_contents("{$g['tmp_path']}/{$gifif}_router",
1403
		    $gif['tunnel-remote-addr']);
1404
	} elseif (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1405
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6",
1406
		    $gif['tunnel-remote-addr']);
1407
	}
1408

    
1409
	route_add_or_change($gif['remote-addr'], $realifgw);
1410

    
1411
	if ($flush) {
1412
		get_interface_arr(true);
1413
	}
1414

    
1415
	interfaces_bring_up($gifif);
1416

    
1417
	return $gifif;
1418
}
1419

    
1420
/*
1421
 * $ipsecifnum = get_ipsecifnum($ikeid, $idx);
1422
 * locates and returns an ipsecifnum in the config.
1423
 */
1424
function get_ipsecifnum($ikeid, $idx) {
1425
	global $config;
1426

    
1427
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1428
	foreach ($config['ipsec']['vtimaps']['item'] as $vtimap) {
1429
		if (($vtimap['reqid'] == $ikeid) &&
1430
		    ($vtimap['index'] == $idx)) {
1431
			return $vtimap['ifnum'];
1432
		}
1433
	}
1434

    
1435
	return false;
1436
}
1437

    
1438
function ipsec_create_vtimap($ikeid, $idx) {
1439
	global $config;
1440

    
1441
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1442

    
1443
	if (count($config['ipsec']['vtimaps']['item']) == 0) {
1444
		return array(
1445
			"reqid" => $ikeid,
1446
			"index" => $idx,
1447
			"ifnum" => 1
1448
		);
1449
	}
1450

    
1451
	$assigned = array_column($config['ipsec']['vtimaps']['item'], 'ifnum');
1452
	asort($assigned, SORT_NUMERIC);
1453
	$new = 1;
1454
	foreach($assigned as $ipsecifnum) {
1455
		if ($ipsecifnum != $new) {
1456
			return array(
1457
				"reqid" => $ikeid,
1458
				"index" => $idx,
1459
				"ifnum" => $new
1460
			);
1461
		}
1462
		if ($new++ > 32767) {
1463
			log_error(gettext("All 32767 ipsec interface numbers " .
1464
			    "have been assigned!"));
1465
			return(NULL);
1466
		}
1467
	}
1468
}
1469

    
1470
function ipsec_del_vtimap($phase2) {
1471
	global $config;
1472

    
1473
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1474

    
1475
	if (count($config['ipsec']['vtimaps']['item']) == 0) {
1476
		return;
1477
	}
1478

    
1479
	$a_vtimaps = &$config['ipsec']['vtimaps']['item'];
1480
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1481
	$last = '';
1482
	foreach ($a_vtimaps as $id => $vtimap) {
1483
		if ($vtimap['reqid'] == $phase1['ikeid']) {
1484
			$last = $id;
1485
		}
1486
	}
1487
	if (!is_numeric($last)) {
1488
		return false;
1489
	}
1490

    
1491
	$vtisubnet_spec = ipsec_vti($phase1, true);
1492
	if (($phase1['iketype'] == 'ikev1') || isset($phase1['splitconn']) ||
1493
	    (count($vtisubnet_spec) == 1)) {
1494
		unset($a_vtimaps[$last]);
1495
		return true;
1496
	}
1497
}
1498

    
1499
function interfaces_tunnel_configure($checkparent = 0, $realif = "", $type = "") {
1500
	global $config;
1501

    
1502
	if (!in_array($type, array('gre', 'gif'))) {
1503
		return;
1504
	}
1505

    
1506
	if (!is_array($config["{$type}s"][$type]) ||
1507
	    !count($config["{$type}s"][$type])) {
1508
		return;
1509
	}
1510

    
1511
	foreach ($config["{$type}s"][$type] as $i => $tunnel) {
1512
		if (empty($tunnel["{$type}if"])) {
1513
			$tunnel["{$type}if"] = $type . $i;
1514
		}
1515
		if (!empty($realif) && $realif != $tunnel["{$type}if"]) {
1516
			continue;
1517
		}
1518

    
1519
		if ($checkparent == 1) {
1520
			if (substr($tunnel['if'], 0, 4) == '_vip') {
1521
				continue;
1522
			}
1523
			if (substr($tunnel['if'], 0, 5) == '_lloc') {
1524
				continue;
1525
			}
1526
			if (!empty($config['interfaces'][$tunnel['if']]) &&
1527
			    $config['interfaces'][$tunnel['if']]['ipaddrv6'] ==
1528
			    "track6") {
1529
				continue;
1530
			}
1531
		} elseif ($checkparent == 2) {
1532
			if ((substr($tunnel['if'], 0, 4) != '_vip' &&
1533
			    substr($tunnel['if'], 0, 5) != '_lloc') &&
1534
			    (empty($config['interfaces'][$tunnel['if']]) ||
1535
			    $config['interfaces'][$tunnel['if']]['ipaddrv6'] !=
1536
			    "track6")) {
1537
				continue;
1538
			}
1539
		}
1540
		if ($type == 'gif') {
1541
			interface_gif_configure($tunnel, "", false);
1542
		} elseif ($type == 'gre') {
1543
			interface_gre_configure($tunnel, "", false);
1544
		}
1545
	}
1546

    
1547
	/* Invalidate cache */
1548
	get_interface_arr(true);
1549
}
1550

    
1551
/* Build a list of IPsec interfaces */
1552
function interface_ipsec_vti_list_p1($ph1ent) {
1553
	global $config;
1554
	$iface_list = array();
1555

    
1556
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1557
		return $iface_list;
1558
	}
1559

    
1560
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1561
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1562
		return $iface_list;
1563
	}
1564

    
1565
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1566
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1567
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1568
			$iface_list["ipsec".get_ipsecifnum($ph1ent['ikeid'], $idx)] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1569
		}
1570
	} else {
1571
		/* For IKEv2, only create one interface with additional addresses as aliases */
1572
		$iface_list["ipsec".get_ipsecifnum($ph1ent['ikeid'], 0)] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1573
	}
1574
	return $iface_list;
1575
}
1576
function interface_ipsec_vti_list_all() {
1577
	global $config;
1578
	$iface_list = array();
1579
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1580
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1581
			if ($ph1ent['disabled']) {
1582
				continue;
1583
			}
1584
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1585
		}
1586
	}
1587
	return $iface_list;
1588
}
1589

    
1590
function is_interface_ipsec_vti_assigned($phase2) {
1591
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1592
	$vti_interface = null;
1593
	$vtisubnet_spec = ipsec_vti($phase1, true);
1594
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1595
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1596
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1597
			foreach ($vtisubnet_spec as $idx => $vtisub) {
1598
				/* Is this for this P2? */
1599
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1600
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1601
					$vti_interface = "ipsec".get_ipsecifnum($phase1['ikeid'], $idx);
1602
				}
1603
			}
1604
		} else {
1605
			$vti_interface = "ipsec".get_ipsecifnum($phase1['ikeid'], 0);
1606
		}
1607
	}
1608
	/* Check if this interface is assigned */
1609
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1610
}
1611
function interface_ipsec_vti_configure($ph1ent) {
1612
	global $config;
1613

    
1614
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1615
		return false;
1616
	}
1617

    
1618
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1619
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1620
		return false;
1621
	}
1622

    
1623
	$left_spec = ipsec_get_phase1_src($ph1ent);
1624
	$right_spec = $ph1ent['remote-gateway'];
1625

    
1626
	$iface_addrs = array();
1627

    
1628
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1629
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1630
		/* Form a single interface for each P2 entry */
1631
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1632
			$ipsecifnum = get_ipsecifnum($ph1ent['ikeid'], $idx);
1633
			if (!is_array($iface_addrs[$ipsecifnum])) {
1634
				$iface_addrs[$ipsecifnum] = array();
1635
			}
1636
			$vtisub['alias'] = "";
1637
			$iface_addrs[$ipsecifnum][] = $vtisub;
1638
		}
1639
	} else {
1640
		/* For IKEv2, only create one interface with additional addresses as aliases */
1641
		$ipsecifnum = get_ipsecifnum($ph1ent['ikeid'], 0);
1642
		if (!is_array($iface_addrs[$ipsecifnum])) {
1643
			$iface_addrs[$ipsecifnum] = array();
1644
		}
1645
		$have_v4 = false;
1646
		$have_v6 = false;
1647
		foreach ($vtisubnet_spec as $vtisub) {
1648
			// Alias stuff
1649
			$vtisub['alias'] = "";
1650
			if (is_ipaddrv6($vtisub['left'])) {
1651
				if ($have_v6) {
1652
					$vtisub['alias'] = " alias";
1653
				}
1654
				$have_v6 = true;
1655
			} else {
1656
				if ($have_v4) {
1657
					$vtisub['alias'] = " alias";
1658
				}
1659
				$have_v4 = true;
1660
			}
1661
			$iface_addrs[$ipsecifnum][] = $vtisub;
1662
		}
1663
	}
1664

    
1665
	foreach ($iface_addrs as $ipsecifnum => $addrs) {
1666
		$ipsecif = "ipsec{$ipsecifnum}";
1667
		if (!is_array($addrs)) {
1668
			continue;
1669
		}
1670
		// Create IPsec interface
1671
		if (does_interface_exist($ipsecif)) {
1672
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy");
1673
		}
1674
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum));
1675

    
1676
		/* Apply the outer tunnel addresses to the interface */
1677
		$inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
1678
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} tunnel " . escapeshellarg($left_spec) . " " . escapeshellarg($right_spec) . " up");
1679

    
1680
		/* Loop through all of the addresses for this interface and apply them as needed */
1681
		foreach ($addrs as $addr) {
1682
			// apply interface addresses
1683
			if (is_v6($addr['left'])) {
1684
				$inet = "inet6";
1685
				$gwtype = "v6";
1686
				$right = '';
1687
			} else {
1688
				$inet = "inet";
1689
				$gwtype = "";
1690
				$right = escapeshellarg($addr['right']);
1691
			}
1692

    
1693
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . $right . $addr['alias']);
1694
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1695
			if (empty($addr['alias'])) {
1696
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1697
			}
1698
		}
1699
		/* Check/set the MTU if the user configured a custom value.
1700
		 * https://redmine.pfsense.org/issues/9111 */
1701
		$currentvtimtu = get_interface_mtu($ipsecif);
1702
		foreach ($config['interfaces'] as $tmpinterface) {
1703
			if ($tmpinterface['if'] == $ipsecif) {
1704
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1705
					$vtimtu = $tmpinterface['mtu'];
1706
				}
1707
			}
1708
		}
1709
		if (is_numericint($vtimtu)) {
1710
			if ($vtimtu != $currentvtimtu) {
1711
				mwexec("/sbin/ifconfig {$ipsecif} mtu {$vtimtu}");
1712
			}
1713
		}
1714
		system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1715
	}
1716
}
1717

    
1718
function interfaces_ipsec_vti_configure() {
1719
	global $config;
1720
	if (platform_booting()) {
1721
		echo gettext("Configuring IPsec VTI interfaces...");
1722
	}
1723
	if (is_array($config['ipsec']) &&
1724
	    is_array($config['ipsec']['phase1']) &&
1725
	    is_array($config['ipsec']['phase2'])) {
1726
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1727
			if ($ph1ent['disabled']) {
1728
				continue;
1729
			}
1730
			interface_ipsec_vti_configure($ph1ent);
1731
		}
1732
	}
1733
	if (platform_booting()) {
1734
		echo gettext("done.") . "\n";
1735
	}
1736
}
1737

    
1738
function interfaces_configure() {
1739
	global $config, $g;
1740

    
1741
	/* Set up our loopback interface */
1742
	interfaces_loopback_configure();
1743

    
1744
	/* create the unconfigured wireless clones */
1745
	interfaces_create_wireless_clones();
1746

    
1747
	/* set up LAGG virtual interfaces */
1748
	interfaces_lagg_configure();
1749

    
1750
	/* set up VLAN virtual interfaces */
1751
	interfaces_vlan_configure();
1752

    
1753
	interfaces_qinq_configure();
1754

    
1755
	$iflist = get_configured_interface_with_descr(true);
1756
	$delayed_list = array();
1757
	$bridge_list = array();
1758
	$track6_list = array();
1759
	$dhcp6c_list = array();
1760

    
1761
	/* This is needed to speedup interfaces on bootup. */
1762
	$reload = false;
1763
	if (!platform_booting()) {
1764
		$reload = true;
1765
	}
1766

    
1767
	foreach ($iflist as $if => $ifname) {
1768
		$realif = $config['interfaces'][$if]['if'];
1769
		if (!isset($config['interfaces'][$if]['enable'])) {
1770
			interface_bring_down($if, true);
1771
		} elseif (strstr($realif, "bridge")) {
1772
			$bridge_list[$if] = $ifname;
1773
		} elseif (strstr($realif, "gre")) {
1774
			$delayed_list[$if] = $ifname;
1775
		} elseif (strstr($realif, "gif")) {
1776
			$delayed_list[$if] = $ifname;
1777
		} elseif (strstr($realif, "ovpn")) {
1778
			continue;
1779
		} elseif (strstr($realif, "ipsec")) {
1780
			continue;
1781
		} elseif (!empty($config['interfaces'][$if]['ipaddrv6']) &&
1782
		    $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1783
			$track6_list[$if] = $ifname;
1784
		} else {
1785
			/* do not run dhcp6c if track interface does not exists
1786
			 * see https://redmine.pfsense.org/issues/3965
1787
			 * and https://redmine.pfsense.org/issues/11633 */ 
1788
			if (!empty($config['interfaces'][$if]['ipaddrv6']) &&
1789
			    $config['interfaces'][$if]['ipaddrv6'] == "dhcp6") {
1790
				$tr6list = link_interface_to_track6($if);
1791
				if (is_array($tr6list) && !empty($tr6list)) {
1792
					$dhcp6c_list[$if] = $ifname;
1793
					continue;
1794
				}
1795
			}
1796
			if (platform_booting()) {
1797
				printf(gettext("Configuring %s interface..."),
1798
				    $ifname);
1799
			}
1800

    
1801
			if ($g['debug']) {
1802
				log_error(sprintf(gettext("Configuring %s"),
1803
				    $ifname));
1804
			}
1805
			interface_configure($if, $reload);
1806
			if (platform_booting()) {
1807
				echo gettext("done.") . "\n";
1808
			}
1809
		}
1810
	}
1811

    
1812
	/*
1813
	 * NOTE: The following function parameter consists of
1814
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1815
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1816
	 */
1817

    
1818
	/* set up GRE virtual interfaces */
1819
	interfaces_tunnel_configure(1,'','gre');
1820

    
1821
	/* set up GIF virtual interfaces */
1822
	interfaces_tunnel_configure(1,'','gif');
1823

    
1824
	/* set up BRIDGE virtual interfaces */
1825
	interfaces_bridge_configure(1);
1826

    
1827
	foreach ($track6_list as $if => $ifname) {
1828
		if (platform_booting()) {
1829
			printf(gettext("Configuring %s interface..."), $ifname);
1830
		}
1831
		if ($g['debug']) {
1832
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1833
		}
1834

    
1835
		interface_configure($if, $reload);
1836

    
1837
		if (platform_booting()) {
1838
			echo gettext("done.") . "\n";
1839
		}
1840
	}
1841

    
1842
	/* bring up vip interfaces */
1843
	interfaces_vips_configure();
1844

    
1845
	/* set up GRE virtual interfaces */
1846
	interfaces_tunnel_configure(2,'','gre');
1847

    
1848
	/* set up GIF virtual interfaces */
1849
	interfaces_tunnel_configure(2,'','gif');
1850

    
1851
	foreach ($delayed_list as $if => $ifname) {
1852
		if (platform_booting()) {
1853
			printf(gettext("Configuring %s interface..."), $ifname);
1854
		}
1855
		if ($g['debug']) {
1856
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1857
		}
1858

    
1859
		interface_configure($if, $reload);
1860

    
1861
		if (platform_booting()) {
1862
			echo gettext("done.") . "\n";
1863
		}
1864
	}
1865

    
1866
	/* set up BRIDGE virtual interfaces */
1867
	interfaces_bridge_configure(2);
1868

    
1869
	foreach ($bridge_list as $if => $ifname) {
1870
		if (platform_booting()) {
1871
			printf(gettext("Configuring %s interface..."), $ifname);
1872
		}
1873
		if ($g['debug']) {
1874
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1875
		}
1876

    
1877
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1878
		// redmine #3997
1879
		interface_reconfigure($if, $reload);
1880
		interfaces_vips_configure($if);
1881

    
1882
		if (platform_booting()) {
1883
			echo gettext("done.") . "\n";
1884
		}
1885
	}
1886

    
1887
	foreach ($dhcp6c_list as $if => $ifname) {
1888
		if (platform_booting()) {
1889
			printf(gettext("Configuring %s interface..."), $ifname);
1890
		}
1891
		if ($g['debug']) {
1892
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1893
		}
1894

    
1895
		interface_configure($if, $reload);
1896

    
1897
		if (platform_booting()) {
1898
			echo gettext("done.") . "\n";
1899
		}
1900
	}
1901

    
1902
	/* set up IPsec VTI interfaces */
1903
	interfaces_ipsec_vti_configure();
1904

    
1905
	/* configure interface groups */
1906
	interfaces_group_setup();
1907

    
1908
	if (!platform_booting()) {
1909
		/* reconfigure static routes (kernel may have deleted them) */
1910
		system_routing_configure();
1911

    
1912
		/* reload IPsec tunnels */
1913
		ipsec_configure();
1914

    
1915
		/* restart dns servers (defering dhcpd reload) */
1916
		if (isset($config['dnsmasq']['enable'])) {
1917
			services_dnsmasq_configure(false);
1918
		}
1919
		if (isset($config['unbound']['enable'])) {
1920
			services_unbound_configure(false);
1921
		}
1922

    
1923
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1924
		services_dhcpd_configure();
1925
	}
1926

    
1927
	return 0;
1928
}
1929

    
1930
function interface_reconfigure($interface = "wan", $reloadall = false) {
1931
	interface_bring_down($interface);
1932
	interface_configure($interface, $reloadall);
1933
}
1934

    
1935
function interface_vip_bring_down($vip) {
1936
	global $g;
1937

    
1938
	$vipif = get_real_interface($vip['interface']);
1939
	switch ($vip['mode']) {
1940
		case "proxyarp":
1941
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1942
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1943
			}
1944
			break;
1945
		case "ipalias":
1946
			if (does_interface_exist($vipif)) {
1947
				if (is_ipaddrv6($vip['subnet'])) {
1948
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1949
				} else {
1950
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1951
				}
1952
			}
1953
			break;
1954
		case "carp":
1955
			/* XXX: Is enough to delete ip address? */
1956
			if (does_interface_exist($vipif)) {
1957
				if (is_ipaddrv6($vip['subnet'])) {
1958
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1959
				} else {
1960
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1961
				}
1962
			}
1963
			break;
1964
	}
1965
}
1966

    
1967
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1968
	global $config, $g;
1969

    
1970
	if (!isset($config['interfaces'][$interface])) {
1971
		return;
1972
	}
1973

    
1974
	if ($g['debug']) {
1975
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1976
	}
1977

    
1978
	/*
1979
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1980
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1981
	 * Keep this in mind while doing changes here!
1982
	 */
1983
	if ($ifacecfg === false) {
1984
		$ifcfg = $config['interfaces'][$interface];
1985
		$ppps = $config['ppps']['ppp'];
1986
		$realif = get_real_interface($interface);
1987
		$realifv6 = get_real_interface($interface, "inet6", true);
1988
	} elseif (!is_array($ifacecfg)) {
1989
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1990
		$ifcfg = $config['interfaces'][$interface];
1991
		$ppps = $config['ppps']['ppp'];
1992
		$realif = get_real_interface($interface);
1993
		$realifv6 = get_real_interface($interface, "inet6", true);
1994
	} else {
1995
		$ifcfg = $ifacecfg['ifcfg'];
1996
		$ppps = $ifacecfg['ppps'];
1997
		if (isset($ifacecfg['ifcfg']['realif'])) {
1998
			$realif = $ifacecfg['ifcfg']['realif'];
1999
			/* XXX: Any better way? */
2000
			$realifv6 = $realif;
2001
		} else {
2002
			$realif = get_real_interface($interface);
2003
			$realifv6 = get_real_interface($interface, "inet6", true);
2004
		}
2005
	}
2006

    
2007
	switch ($ifcfg['ipaddr']) {
2008
		case "ppp":
2009
		case "pppoe":
2010
		case "pptp":
2011
		case "l2tp":
2012
			if (is_array($ppps) && count($ppps)) {
2013
				foreach ($ppps as $pppid => $ppp) {
2014
					if ($realif == $ppp['if']) {
2015
						if (isset($ppp['ondemand']) && !$destroy) {
2016
							send_event("interface reconfigure {$interface}");
2017
							break;
2018
						}
2019
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
2020
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
2021
							sleep(2);
2022
						}
2023
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
2024
						break;
2025
					}
2026
				}
2027
			}
2028
			break;
2029
		case "dhcp":
2030
			kill_dhclient_process($realif);
2031
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
2032
			if (does_interface_exist("$realif")) {
2033
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
2034
				interface_vip_cleanup($interface, "inet4");
2035
				if ($destroy == true) {
2036
					pfSense_interface_flags($realif, -IFF_UP);
2037
				}
2038
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2039
			}
2040
			break;
2041
		default:
2042
			if (does_interface_exist("$realif")) {
2043
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
2044
				interface_vip_cleanup($interface, "inet4");
2045
				if ($destroy == true) {
2046
					pfSense_interface_flags($realif, -IFF_UP);
2047
				}
2048
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2049
			}
2050
			break;
2051
	}
2052

    
2053
	$track6 = array();
2054
	switch ($ifcfg['ipaddrv6']) {
2055
		case "slaac":
2056
		case "dhcp6":
2057
			kill_dhcp6client_process($realif, $destroy, false);
2058
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
2059
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
2060
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh");
2061
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
2062
			if (does_interface_exist($realifv6)) {
2063
				mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 -accept_rtadv");
2064
				$ip6 = find_interface_ipv6($realifv6);
2065
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
2066
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
2067
				}
2068
				interface_vip_cleanup($interface, "inet6");
2069
				if ($destroy == true) {
2070
					pfSense_interface_flags($realif, -IFF_UP);
2071
				}
2072
			}
2073
			$track6 = link_interface_to_track6($interface);
2074
			break;
2075
		case "6rd":
2076
		case "6to4":
2077
			$realif = "{$interface}_stf";
2078
			if (does_interface_exist("$realif")) {
2079
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
2080
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
2081
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
2082
					$destroy = true;
2083
				} else {
2084
					/* get_interface_ipv6() returns empty value if interface is being disabled */
2085
					$ip6 = get_interface_ipv6($interface);
2086
					if (is_ipaddrv6($ip6)) {
2087
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2088
					}
2089
				}
2090
				interface_vip_cleanup($interface, "inet6");
2091
				if ($destroy == true) {
2092
					pfSense_interface_flags($realif, -IFF_UP);
2093
				}
2094
			}
2095
			$track6 = link_interface_to_track6($interface);
2096
			break;
2097
		default:
2098
			if (does_interface_exist("$realif")) {
2099
				$ip6 = get_interface_ipv6($interface);
2100
				if (is_ipaddrv6($ip6)) {
2101
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2102
				}
2103
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
2104
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
2105
				}
2106
				interface_vip_cleanup($interface, "inet6");
2107
				if ($destroy == true) {
2108
					pfSense_interface_flags($realif, -IFF_UP);
2109
				}
2110
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2111
			}
2112
			$track6 = link_interface_to_track6($interface);
2113
			break;
2114
	}
2115

    
2116
	if (!empty($track6) && is_array($track6)) {
2117
		if (!function_exists('services_dhcpd_configure')) {
2118
			require_once('services.inc');
2119
		}
2120
		/* Bring down radvd and dhcp6 on these interfaces */
2121
		services_dhcpd_configure('inet6', $track6);
2122
	}
2123

    
2124
	$old_router = '';
2125
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
2126
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
2127
	}
2128

    
2129
	/* remove interface up file if it exists */
2130
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
2131
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
2132
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
2133
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
2134
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
2135
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
2136
	unlink_if_exists("{$g['varetc_path']}/nameserver_v6{$interface}");
2137
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
2138
	unlink_if_exists("{$g['varetc_path']}/searchdomain_v6{$interface}");
2139

    
2140
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
2141
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
2142
	if (is_array($ifcfg['wireless'])) {
2143
		kill_hostapd($realif);
2144
		mwexec(kill_wpasupplicant($realif));
2145
		unlink_if_exists("{$g['varetc_path']}/wpa_supplicant_{$realif}.*");
2146
		unlink_if_exists("{$g['varetc_path']}/hostapd_{$realif}.conf");
2147
	}
2148

    
2149
	if ($destroy == true) {
2150
		if (preg_match("/^[a-z0-9]+^tun|^ovpn|^ipsec|^gif|^gre|^lagg|^bridge|vlan|_stf$/i", $realif)) {
2151
			pfSense_interface_destroy($realif);
2152

    
2153
			/* Invalidate cache */
2154
			get_interface_arr(true);
2155
		}
2156
	}
2157

    
2158
	return;
2159
}
2160

    
2161
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
2162
	global $config;
2163
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
2164
		unset($config["virtualip_carp_maintenancemode"]);
2165
		write_config("Leave CARP maintenance mode");
2166
	} elseif (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
2167
		$config["virtualip_carp_maintenancemode"] = true;
2168
		write_config(gettext("Enter CARP maintenance mode"));
2169
	}
2170
	init_config_arr(array('virtualip', 'vip'));
2171
	$viparr = &$config['virtualip']['vip'];
2172

    
2173
	if (is_array($viparr)) {
2174
		foreach ($viparr as $vip) {
2175
			if ($vip['mode'] == "carp") {
2176
				interface_carp_configure($vip, true);
2177
			}
2178
		}
2179
	}
2180
}
2181

    
2182
function interface_wait_tentative($interface, $timeout = 10) {
2183
	if (!does_interface_exist($interface)) {
2184
		return false;
2185
	}
2186

    
2187
	$time = 0;
2188
	while ($time <= $timeout) {
2189
		$if = pfSense_get_interface_addresses($interface);
2190
		if (!isset($if['tentative'])) {
2191
			return true;
2192
		}
2193
		sleep(1);
2194
		$time++;
2195
	}
2196

    
2197
	return false;
2198
}
2199

    
2200
function interface_isppp_type($interface) {
2201
	global $config;
2202

    
2203
	if (!is_array($config['interfaces'][$interface])) {
2204
		return false;
2205
	}
2206

    
2207
	switch ($config['interfaces'][$interface]['ipaddr']) {
2208
		case 'pptp':
2209
		case 'l2tp':
2210
		case 'pppoe':
2211
		case 'ppp':
2212
			return true;
2213
			break;
2214
		default:
2215
			return false;
2216
			break;
2217
	}
2218
}
2219

    
2220
function interfaces_ptpid_used($ptpid) {
2221
	global $config;
2222

    
2223
	if (is_array($config['ppps']['ppp'])) {
2224
		foreach ($config['ppps']['ppp'] as & $settings) {
2225
			if ($ptpid == $settings['ptpid']) {
2226
				return true;
2227
			}
2228
		}
2229
	}
2230

    
2231
	return false;
2232
}
2233

    
2234
function interfaces_ptpid_next() {
2235

    
2236
	$ptpid = 0;
2237
	while (interfaces_ptpid_used($ptpid)) {
2238
		$ptpid++;
2239
	}
2240

    
2241
	return $ptpid;
2242
}
2243

    
2244
function getMPDCRONSettings($pppif) {
2245
	global $config;
2246

    
2247
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2248
	if (is_array($config['cron']['item'])) {
2249
		foreach ($config['cron']['item'] as $i => $item) {
2250
			if (stripos($item['command'], $cron_cmd_file) !== false) {
2251
				return array("ID" => $i, "ITEM" => $item);
2252
			}
2253
		}
2254
	}
2255

    
2256
	return NULL;
2257
}
2258

    
2259
function handle_pppoe_reset($post_array) {
2260
	global $config, $g;
2261

    
2262
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2263
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2264

    
2265
	if (!is_array($config['cron']['item'])) {
2266
		$config['cron']['item'] = array();
2267
	}
2268

    
2269
	$itemhash = getMPDCRONSettings($pppif);
2270

    
2271
	// reset cron items if necessary and return
2272
	if (empty($post_array['pppoe-reset-type'])) {
2273
		if (isset($itemhash)) {
2274
			unset($config['cron']['item'][$itemhash['ID']]);
2275
		}
2276
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2277
		return;
2278
	}
2279

    
2280
	if (empty($itemhash)) {
2281
		$itemhash = array();
2282
	}
2283
	$item = array();
2284
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
2285
		$item['minute'] = $post_array['pppoe_resetminute'];
2286
		$item['hour'] = $post_array['pppoe_resethour'];
2287
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
2288
			$date = explode("/", $post_array['pppoe_resetdate']);
2289
			$item['mday'] = $date[1];
2290
			$item['month'] = $date[0];
2291
		} else {
2292
			$item['mday'] = "*";
2293
			$item['month'] = "*";
2294
		}
2295
		$item['wday'] = "*";
2296
		$item['who'] = "root";
2297
		$item['command'] = $cron_cmd_file;
2298
	} elseif (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
2299
		switch ($post_array['pppoe_pr_preset_val']) {
2300
			case "monthly":
2301
				$item['minute'] = "0";
2302
				$item['hour'] = "0";
2303
				$item['mday'] = "1";
2304
				$item['month'] = "*";
2305
				$item['wday'] = "*";
2306
				break;
2307
			case "weekly":
2308
				$item['minute'] = "0";
2309
				$item['hour'] = "0";
2310
				$item['mday'] = "*";
2311
				$item['month'] = "*";
2312
				$item['wday'] = "0";
2313
				break;
2314
			case "daily":
2315
				$item['minute'] = "0";
2316
				$item['hour'] = "0";
2317
				$item['mday'] = "*";
2318
				$item['month'] = "*";
2319
				$item['wday'] = "*";
2320
				break;
2321
			case "hourly":
2322
				$item['minute'] = "0";
2323
				$item['hour'] = "*";
2324
				$item['mday'] = "*";
2325
				$item['month'] = "*";
2326
				$item['wday'] = "*";
2327
				break;
2328
		} // end switch
2329
		$item['who'] = "root";
2330
		$item['command'] = $cron_cmd_file;
2331
	}
2332
	if (empty($item)) {
2333
		return;
2334
	}
2335
	if (isset($itemhash['ID'])) {
2336
		$config['cron']['item'][$itemhash['ID']] = $item;
2337
	} else {
2338
		$config['cron']['item'][] = $item;
2339
	}
2340
}
2341

    
2342
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2343
	global $config;
2344
	$ppp_list = array();
2345
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2346
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2347
			$ports = explode(",", $ppp['ports']);
2348
			foreach($ports as $port) {
2349
				foreach($triggerinterfaces as $vip) {
2350
					if ($port == "_vip{$vip['uniqid']}") {
2351
						$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2352
						$ppp_list[$if] = 1;
2353
					}
2354
				}
2355
			}
2356
		}
2357
	}
2358
	foreach($ppp_list as $pppif => $dummy) {
2359
		interface_ppps_configure($pppif);
2360
	}
2361
}
2362

    
2363
/*
2364
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2365
 * It writes the mpd config file to /var/etc every time the link is opened.
2366
 */
2367
function interface_ppps_configure($interface) {
2368
	global $config, $g;
2369

    
2370
	/* Return for unassigned interfaces. This is a minimum requirement. */
2371
	if (empty($config['interfaces'][$interface])) {
2372
		return 0;
2373
	}
2374
	$ifcfg = $config['interfaces'][$interface];
2375
	if (!isset($ifcfg['enable'])) {
2376
		return 0;
2377
	}
2378

    
2379
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2380
	if (!is_dir("/var/spool/lock")) {
2381
		mkdir("/var/spool/lock", 0777, true);
2382
	}
2383
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2384
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2385
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2386
	}
2387

    
2388
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2389
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2390
			if ($ifcfg['if'] == $ppp['if']) {
2391
				break;
2392
			}
2393
		}
2394
	}
2395
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2396
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2397
		return 0;
2398
	}
2399
	$pppif = $ifcfg['if'];
2400
	if ($ppp['type'] == "ppp") {
2401
		$type = "modem";
2402
	} else {
2403
		$type = $ppp['type'];
2404
	}
2405
	$upper_type = strtoupper($ppp['type']);
2406

    
2407
	$confports = explode(',', $ppp['ports']);
2408
	if ($type == "modem") {
2409
		$ports = $confports;
2410
	} else {
2411
		$ports = array();
2412
		foreach ($confports as $pid => $port) {
2413
			if (strstr($port, "_vip")) {
2414
				if (get_carp_interface_status($port) != "MASTER") {
2415
					continue;
2416
				}
2417
			}
2418
			$ports[$pid] = get_real_interface($port);
2419
			if (empty($ports[$pid])) {
2420
				return 0;
2421
			}
2422
		}
2423
	}
2424
	$localips = explode(',', $ppp['localip']);
2425
	$gateways = explode(',', $ppp['gateway']);
2426
	$subnets = explode(',', $ppp['subnet']);
2427

    
2428
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2429
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2430
	 */
2431
	foreach ($ports as $pid => $port) {
2432
		switch ($ppp['type']) {
2433
			case "pppoe":
2434
				/* Bring the parent interface up */
2435
				interfaces_bring_up($port);
2436
				pfSense_ngctl_attach(".", $port);
2437
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2438
				$ngif = str_replace(".", "_", $port);
2439
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2440
				break;
2441
			case "pptp":
2442
			case "l2tp":
2443
				/* configure interface */
2444
				if (is_ipaddr($localips[$pid])) {
2445
					// Manually configure interface IP/subnet
2446
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2447
					interfaces_bring_up($port);
2448
				} elseif (empty($localips[$pid])) {
2449
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2450
				}
2451

    
2452
				if (!is_ipaddr($localips[$pid])) {
2453
					log_error(sprintf(gettext("Could not get a Local IP address for PPTP/L2TP link on %s in interfaces_ppps_configure. Using 0.0.0.0 ip!"), $port));
2454
					$localips[$pid] = "0.0.0.0";
2455
				}
2456
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2457
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2458
				}
2459
				if (!is_ipaddr($gateways[$pid])) {
2460
					log_error(sprintf(gettext('Could not get a PPTP/L2TP Remote IP address from %1$s for %2$s in interfaces_ppps_configure.'), $dhcp_gateway, $gway));
2461
					return 0;
2462
				}
2463
				pfSense_ngctl_attach(".", $port);
2464
				break;
2465
			case "ppp":
2466
				if (!file_exists("{$port}")) {
2467
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2468
					return 0;
2469
				}
2470
				break;
2471
			default:
2472
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2473
				break;
2474
		}
2475
	}
2476

    
2477
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2478
	    (is_array($ports) && count($ports) > 1)) {
2479
		$multilink = "enable";
2480
	} else {
2481
		$multilink = "disable";
2482
	}
2483

    
2484
	if ($type == "modem") {
2485
		if (is_ipaddr($ppp['localip'])) {
2486
			$localip = $ppp['localip'];
2487
		} else {
2488
			$localip = '0.0.0.0';
2489
		}
2490

    
2491
		if (is_ipaddr($ppp['gateway'])) {
2492
			$gateway = $ppp['gateway'];
2493
		} else {
2494
			$gateway = "10.64.64.{$pppid}";
2495
		}
2496
		$ranges = "{$localip}/0 {$gateway}/0";
2497

    
2498
		if (empty($ppp['apnum'])) {
2499
			$ppp['apnum'] = 1;
2500
		}
2501
	} else {
2502
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2503
	}
2504

    
2505
	if (isset($ppp['ondemand'])) {
2506
		$ondemand = "enable";
2507
	} else {
2508
		$ondemand = "disable";
2509
	}
2510
	if (!isset($ppp['idletimeout'])) {
2511
		$ppp['idletimeout'] = 0;
2512
	}
2513

    
2514
	if (empty($ppp['username']) && $type == "modem") {
2515
		$ppp['username'] = "user";
2516
		$ppp['password'] = "none";
2517
	}
2518
	if (empty($ppp['password']) && $type == "modem") {
2519
		$passwd = "none";
2520
	} else {
2521
		$passwd = base64_decode($ppp['password']);
2522
	}
2523

    
2524
	$bandwidths = explode(',', $ppp['bandwidth']);
2525
	$defaultmtu = "1492";
2526
	if (!empty($ifcfg['mtu'])) {
2527
		$defaultmtu = intval($ifcfg['mtu']);
2528
	}
2529
	if (isset($ppp['mtu'])) {
2530
		$mtus = explode(',', $ppp['mtu']);
2531
	}
2532
	if (isset($ppp['mru'])) {
2533
		$mrus = explode(',', $ppp['mru']);
2534
	}
2535
	if (isset($ppp['mrru'])) {
2536
		$mrrus = explode(',', $ppp['mrru']);
2537
	}
2538
	if (!empty($ifcfg['ipaddrv6'])) {
2539
		$ipv6cp = "set bundle enable ipv6cp";
2540
	}
2541

    
2542
	// Construct the mpd.conf file
2543
	$mpdconf = <<<EOD
2544
startup:
2545
	# configure the console
2546
	set console close
2547
	# configure the web server
2548
	set web close
2549

    
2550
default:
2551
{$ppp['type']}client:
2552
	create bundle static {$interface}
2553
	{$ipv6cp}
2554
	set iface name {$pppif}
2555

    
2556
EOD;
2557
	$setdefaultgw = false;
2558
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2559
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2560
	if ($defgw4['interface'] == $interface) {
2561
		$setdefaultgw = true;
2562
	}
2563

    
2564
/* Omit this, we maintain the default route by other means, and it causes problems with
2565
 * default gateway switching. See redmine #1837 for original issue
2566
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2567
 * edge case. redmine #6495 open to address.
2568
 */
2569
	if ($setdefaultgw == true) {
2570
		$mpdconf .= <<<EOD
2571
	set iface route default
2572

    
2573
EOD;
2574
	}
2575

    
2576
	$mpdconf .= <<<EOD
2577
	set iface {$ondemand} on-demand
2578
	set iface idle {$ppp['idletimeout']}
2579

    
2580
EOD;
2581

    
2582
	if (isset($ppp['ondemand'])) {
2583
		$mpdconf .= <<<EOD
2584
	set iface addrs 10.10.1.1 10.10.1.2
2585

    
2586
EOD;
2587
	}
2588

    
2589
	if (isset($ppp['mtu-override']) &&
2590
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2591
		/* Find the smaller MTU set on ports */
2592
		$mtu = $defaultmtu;
2593
		foreach ($ports as $pid => $port) {
2594
			if (empty($mtus[$pid])) {
2595
				$mtus[$pid] = $defaultmtu;
2596
			}
2597
			if ($type == "pppoe") {
2598
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2599
					$mtus[$pid] = get_interface_mtu($port) - 8;
2600
				}
2601
			}
2602
			if ($mtu > $mtus[$pid]) {
2603
				$mtu = $mtus[$pid];
2604
			}
2605
		}
2606
		$mpdconf .= <<<EOD
2607
	set iface mtu {$mtu} override
2608

    
2609
EOD;
2610
	}
2611

    
2612
	if (isset($ppp['tcpmssfix'])) {
2613
		$tcpmss = "disable";
2614
	} else {
2615
		$tcpmss = "enable";
2616
	}
2617
	$mpdconf .= <<<EOD
2618
	set iface {$tcpmss} tcpmssfix
2619

    
2620
EOD;
2621

    
2622
	$mpdconf .= <<<EOD
2623
	set iface up-script /usr/local/sbin/ppp-linkup
2624
	set iface down-script /usr/local/sbin/ppp-linkdown
2625
	set ipcp ranges {$ranges}
2626

    
2627
EOD;
2628
	if (isset($ppp['vjcomp'])) {
2629
		$mpdconf .= <<<EOD
2630
	set ipcp no vjcomp
2631

    
2632
EOD;
2633
	}
2634

    
2635
	if (isset($config['system']['dnsallowoverride'])) {
2636
		$mpdconf .= <<<EOD
2637
	set ipcp enable req-pri-dns
2638
	set ipcp enable req-sec-dns
2639

    
2640
EOD;
2641
	}
2642

    
2643
	if (!isset($ppp['verbose_log'])) {
2644
		$mpdconf .= <<<EOD
2645
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2646

    
2647
EOD;
2648
	}
2649

    
2650
	foreach ($ports as $pid => $port) {
2651
		$port = get_real_interface($port);
2652
		$mpdconf .= <<<EOD
2653

    
2654
	create link static {$interface}_link{$pid} {$type}
2655
	set link action bundle {$interface}
2656
	set link {$multilink} multilink
2657
	set link keep-alive 10 60
2658
	set link max-redial 0
2659

    
2660
EOD;
2661
		if (isset($ppp['shortseq'])) {
2662
			$mpdconf .= <<<EOD
2663
	set link no shortseq
2664

    
2665
EOD;
2666
		}
2667

    
2668
		if (isset($ppp['acfcomp'])) {
2669
			$mpdconf .= <<<EOD
2670
	set link no acfcomp
2671

    
2672
EOD;
2673
		}
2674

    
2675
		if (isset($ppp['protocomp'])) {
2676
			$mpdconf .= <<<EOD
2677
	set link no protocomp
2678

    
2679
EOD;
2680
		}
2681

    
2682
		$mpdconf .= <<<EOD
2683
	set link disable chap pap
2684
	set link accept chap pap eap
2685
	set link disable incoming
2686

    
2687
EOD;
2688

    
2689

    
2690
		if (!empty($bandwidths[$pid])) {
2691
			$mpdconf .= <<<EOD
2692
	set link bandwidth {$bandwidths[$pid]}
2693

    
2694
EOD;
2695
		}
2696

    
2697
		if (empty($mtus[$pid])) {
2698
			$mtus[$pid] = $defaultmtu;
2699
		}
2700
		if ($type == "pppoe") {
2701
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2702
				$mtus[$pid] = get_interface_mtu($port) - 8;
2703
			}
2704
		}
2705
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2706
		    !isset($ppp['mtu-override']) &&
2707
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2708
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2709
			$mpdconf .= <<<EOD
2710
	set link mtu {$mtus[$pid]}
2711

    
2712
EOD;
2713
		}
2714

    
2715
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2716
		    !isset($ppp['mtu-override']) &&
2717
		    !empty($mrus[$pid])) {
2718
			$mpdconf .= <<<EOD
2719
	set link mru {$mrus[$pid]}
2720

    
2721
EOD;
2722
		}
2723

    
2724
		if (!empty($mrrus[$pid])) {
2725
			$mpdconf .= <<<EOD
2726
	set link mrru {$mrrus[$pid]}
2727

    
2728
EOD;
2729
		}
2730

    
2731
		$mpdconf .= <<<EOD
2732
	set auth authname "{$ppp['username']}"
2733
	set auth password {$passwd}
2734

    
2735
EOD;
2736
		if ($type == "modem") {
2737
			$mpdconf .= <<<EOD
2738
	set modem device {$ppp['ports']}
2739
	set modem script DialPeer
2740
	set modem idle-script Ringback
2741
	set modem watch -cd
2742
	set modem var \$DialPrefix "DT"
2743
	set modem var \$Telephone "{$ppp['phone']}"
2744

    
2745
EOD;
2746
		}
2747
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2748
			$mpdconf .= <<<EOD
2749
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2750

    
2751
EOD;
2752
		}
2753
		if (isset($ppp['initstr']) && $type == "modem") {
2754
			$initstr = base64_decode($ppp['initstr']);
2755
			$mpdconf .= <<<EOD
2756
	set modem var \$InitString "{$initstr}"
2757

    
2758
EOD;
2759
		}
2760
		if (isset($ppp['simpin']) && $type == "modem") {
2761
			if ($ppp['pin-wait'] == "") {
2762
				$ppp['pin-wait'] = 0;
2763
			}
2764
			$mpdconf .= <<<EOD
2765
	set modem var \$SimPin "{$ppp['simpin']}"
2766
	set modem var \$PinWait "{$ppp['pin-wait']}"
2767

    
2768
EOD;
2769
		}
2770
		if (isset($ppp['apn']) && $type == "modem") {
2771
			$mpdconf .= <<<EOD
2772
	set modem var \$APN "{$ppp['apn']}"
2773
	set modem var \$APNum "{$ppp['apnum']}"
2774

    
2775
EOD;
2776
		}
2777
		if ($type == "pppoe") {
2778
			$hostuniq = '';
2779
			if (!empty($ppp['hostuniq'])) {
2780
				if (preg_match('/^0x[a-fA-F0-9]+$/', $ppp['hostuniq'])) {
2781
					$hostuniq = strtolower($ppp['hostuniq']) .'|';
2782
				} elseif (preg_match('/^[a-zA-Z0-9]+$/i', $ppp['hostuniq'])) {
2783
					$hostuniq = '0x' . bin2hex($ppp['hostuniq']) . '|';
2784
				}
2785
			}
2786
			// Send a null service name if none is set.
2787
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2788
			$mpdconf .= <<<EOD
2789
	set pppoe service "{$hostuniq}{$provider}"
2790

    
2791
EOD;
2792
		}
2793
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2794
			$mpdconf .= <<<EOD
2795
	set pppoe max-payload {$mtus[$pid]}
2796

    
2797
EOD;
2798
		}
2799
		if ($type == "pppoe") {
2800
			$mpdconf .= <<<EOD
2801
	set pppoe iface {$port}
2802

    
2803
EOD;
2804
		}
2805

    
2806
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2807
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2808
			$mpdconf .= <<<EOD
2809
	set l2tp secret "{$secret}"
2810

    
2811
EOD;
2812
		}
2813

    
2814
		if (($type == "pptp") || ($type == "l2tp")) {
2815
			$mpdconf .= <<<EOD
2816
	set {$type} self {$localips[$pid]}
2817
	set {$type} peer {$gateways[$pid]}
2818

    
2819
EOD;
2820
		}
2821

    
2822
		$mpdconf .= "\topen\n";
2823
	} //end foreach ($port)
2824

    
2825

    
2826
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2827
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2828
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2829
	} else {
2830
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2831
		if (!$fd) {
2832
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2833
			return 0;
2834
		}
2835
		// Write out mpd_ppp.conf
2836
		fwrite($fd, $mpdconf);
2837
		fclose($fd);
2838
		unset($mpdconf);
2839
	}
2840

    
2841
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2842
	if (isset($ppp['uptime'])) {
2843
		if (!file_exists("/conf/{$pppif}.log")) {
2844
			file_put_contents("/conf/{$pppif}.log", '');
2845
		}
2846
	} else {
2847
		if (file_exists("/conf/{$pppif}.log")) {
2848
			@unlink("/conf/{$pppif}.log");
2849
		}
2850
	}
2851

    
2852
	/* clean up old lock files */
2853
	foreach ($ports as $port) {
2854
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2855
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2856
		}
2857
	}
2858

    
2859
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2860
	/* random IPv6 interface identifier during boot. More details at */
2861
	/* https://forum.netgate.com/post/592474 */
2862
	if (platform_booting() && is_array($config['interfaces'])) {
2863
		$count = 0;
2864
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2865
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2866
				$tempaddr[$count]['if'] = $tempiface['if'];
2867
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2868
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2869
				$count++;
2870
			}
2871
			// Maximum /31 is is x.y.z.254/31
2872
			if ($count > 122) {
2873
				break;
2874
			}
2875
		}
2876
		unset($count);
2877
	}
2878

    
2879
	/* fire up mpd */
2880
	mwexec("/usr/local/sbin/mpd5 -b -k -d {$g['varetc_path']} -f mpd_{$interface}.conf -p " .
2881
		escapeshellarg("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid") . " -s ppp " .
2882
		escapeshellarg("{$ppp['type']}client"));
2883

    
2884
	// Check for PPPoE periodic reset request
2885
	if ($type == "pppoe") {
2886
		if (!empty($ppp['pppoe-reset-type'])) {
2887
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2888
		} else {
2889
			interface_setup_pppoe_reset_file($ppp['if']);
2890
		}
2891
	}
2892
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2893
	$i = 0;
2894
	while ($i < 10) {
2895
		if (does_interface_exist($ppp['if'], true)) {
2896
			break;
2897
		}
2898
		sleep(3);
2899
		$i++;
2900
	}
2901

    
2902
	/* Remove all temporary bogon IPv4 addresses */
2903
	if (is_array($tempaddr)) {
2904
		foreach ($tempaddr as $tempiface) {
2905
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2906
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2907
			}
2908
		}
2909
		unset ($tempaddr);
2910
	}
2911

    
2912
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2913
	/* We should be able to launch the right version for each modem */
2914
	/* We can also guess the mondev from the manufacturer */
2915
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2916
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2917
	foreach ($ports as $port) {
2918
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2919
			$mondev = substr(basename($port), 0, -1);
2920
			$devlist = glob("/dev/{$mondev}?");
2921
			$mondev = basename(end($devlist));
2922
		}
2923
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2924
			$mondev = substr(basename($port), 0, -1) . "1";
2925
		}
2926
		if ($mondev != '') {
2927
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2928
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2929
		}
2930
	}
2931

    
2932
	return 1;
2933
}
2934

    
2935
function interfaces_sync_setup() {
2936
	global $g, $config;
2937

    
2938
	if (isset($config['system']['developerspew'])) {
2939
		$mt = microtime();
2940
		echo "interfaces_sync_setup() being called $mt\n";
2941
	}
2942

    
2943
	if (platform_booting()) {
2944
		echo gettext("Configuring CARP settings...");
2945
		mute_kernel_msgs();
2946
	}
2947

    
2948
	/* suck in configuration items */
2949
	if ($config['hasync']) {
2950
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2951
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2952
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2953
	}
2954

    
2955
	set_sysctl(array(
2956
		"net.inet.carp.preempt" => "1",
2957
		"net.inet.carp.log" => "1")
2958
	);
2959

    
2960
	if (!empty($pfsyncinterface)) {
2961
		$carp_sync_int = get_real_interface($pfsyncinterface);
2962
	}
2963

    
2964
	/* setup pfsync interface */
2965
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2966
		if (is_ipaddr($pfsyncpeerip)) {
2967
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2968
		} else {
2969
			$syncpeer = "-syncpeer";
2970
		}
2971

    
2972
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} " .
2973
		    "{$syncpeer} up");
2974
		mwexec("/sbin/ifconfig pfsync0 -defer");
2975

    
2976
		/*
2977
		 * XXX: Handle an issue with pfsync(4) and carp(4). In a
2978
		 * cluster carp will come up before pfsync(4) has updated and
2979
		 * so will cause issues for existing sessions.
2980
		 */
2981
		log_error(gettext("waiting for pfsync..."));
2982

    
2983
		$i = 0;
2984
		do {
2985
			sleep(1);
2986
			$_gb = exec('/sbin/ifconfig pfsync0 | ' .
2987
			    '/usr/bin/grep -q "syncok: 0" 2>/dev/null', $output,
2988
			    $rc);
2989
			$i++;
2990
		} while ($rc != 0 && $i <= 30);
2991

    
2992
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2993
		log_error(gettext("Configuring CARP settings finalize..."));
2994
	} else {
2995
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down");
2996
	}
2997

    
2998
	$carplist = get_configured_vip_list('all', VIP_CARP);
2999
	if (is_array($carplist) && count($carplist) > 0) {
3000
		set_single_sysctl("net.inet.carp.allow", "1");
3001
	} else {
3002
		set_single_sysctl("net.inet.carp.allow", "0");
3003
	}
3004

    
3005
	if (platform_booting()) {
3006
		unmute_kernel_msgs();
3007
		echo gettext("done.") . "\n";
3008
	}
3009
}
3010

    
3011
function interface_proxyarp_configure($interface = "") {
3012
	global $config, $g;
3013
	if (isset($config['system']['developerspew'])) {
3014
		$mt = microtime();
3015
		echo "interface_proxyarp_configure() being called $mt\n";
3016
	}
3017

    
3018
	/* kill any running choparp */
3019
	if (empty($interface)) {
3020
		killbyname("choparp");
3021
	} else {
3022
		$vipif = get_real_interface($interface);
3023
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
3024
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
3025
		}
3026
	}
3027

    
3028
	$paa = array();
3029
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
3030

    
3031
		/* group by interface */
3032
		foreach ($config['virtualip']['vip'] as $vipent) {
3033
			if ($vipent['mode'] === "proxyarp") {
3034
				if ($vipent['interface']) {
3035
					$proxyif = $vipent['interface'];
3036
				} else {
3037
					$proxyif = "wan";
3038
				}
3039

    
3040
				if (!empty($interface) && $interface != $proxyif) {
3041
					continue;
3042
				}
3043

    
3044
				if (!is_array($paa[$proxyif])) {
3045
					$paa[$proxyif] = array();
3046
				}
3047

    
3048
				$paa[$proxyif][] = $vipent;
3049
			}
3050
		}
3051
	}
3052

    
3053
	if (!empty($interface)) {
3054
		if (is_array($paa[$interface])) {
3055
			$paaifip = get_interface_ip($interface);
3056
			if (!is_ipaddr($paaifip)) {
3057
				return;
3058
			}
3059
			$vipif = get_real_interface($interface);
3060
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
3061
			$args .= $vipif . " auto";
3062
			foreach ($paa[$interface] as $paent) {
3063
				if (isset($paent['subnet'])) {
3064
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
3065
				} elseif (isset($paent['range'])) {
3066
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
3067
				}
3068
			}
3069
			mwexec_bg("/usr/local/sbin/choparp " . $args);
3070
		}
3071
	} elseif (count($paa) > 0) {
3072
		foreach ($paa as $paif => $paents) {
3073
			$paaifip = get_interface_ip($paif);
3074
			if (!is_ipaddr($paaifip)) {
3075
				continue;
3076
			}
3077
			$vipif = get_real_interface($paif);
3078
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
3079
			$args .= $vipif . " auto";
3080
			foreach ($paents as $paent) {
3081
				if (isset($paent['subnet'])) {
3082
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
3083
				} elseif (isset($paent['range'])) {
3084
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
3085
				}
3086
			}
3087
			mwexec_bg("/usr/local/sbin/choparp " . $args);
3088
		}
3089
	}
3090
}
3091

    
3092
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
3093
	global $g, $config;
3094

    
3095
	if (is_array($config['virtualip']['vip'])) {
3096
		foreach ($config['virtualip']['vip'] as $vip) {
3097

    
3098
			$iface = $vip['interface'];
3099
			if (substr($iface, 0, 4) == "_vip")
3100
				$iface = get_configured_vip_interface($vip['interface']);
3101
			if ($iface != $interface)
3102
				continue;
3103
			if ($type == VIP_CARP) {
3104
				if ($vip['mode'] != "carp")
3105
					continue;
3106
			} elseif ($type == VIP_IPALIAS) {
3107
				if ($vip['mode'] != "ipalias")
3108
					continue;
3109
			} else {
3110
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
3111
					continue;
3112
			}
3113

    
3114
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
3115
				interface_vip_bring_down($vip);
3116
			elseif ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
3117
				interface_vip_bring_down($vip);
3118
			elseif ($inet == "all")
3119
				interface_vip_bring_down($vip);
3120
		}
3121
	}
3122
}
3123

    
3124
function interfaces_vips_configure($interface = "") {
3125
	global $g, $config;
3126
	if (isset($config['system']['developerspew'])) {
3127
		$mt = microtime();
3128
		echo "interfaces_vips_configure() being called $mt\n";
3129
	}
3130

    
3131
	if (!is_array($config['virtualip']['vip'])) {
3132
		return;
3133
	}
3134

    
3135
	$carp_setuped = false;
3136
	$anyproxyarp = false;
3137
	foreach ($config['virtualip']['vip'] as $vip) {
3138
		if ($interface <> "" &&
3139
		    get_root_interface($vip['interface']) <> $interface) {
3140
			continue;
3141
		}
3142
		switch ($vip['mode']) {
3143
			case "proxyarp":
3144
				/*
3145
				 * nothing it is handled on
3146
				 * interface_proxyarp_configure()
3147
				 */
3148
				$anyproxyarp = true;
3149
				break;
3150
			case "ipalias":
3151
				interface_ipalias_configure($vip);
3152
				break;
3153
			case "carp":
3154
				if ($carp_setuped == false) {
3155
					$carp_setuped = true;
3156
				}
3157
				interface_carp_configure($vip);
3158
				break;
3159
		}
3160
	}
3161
	if ($carp_setuped == true) {
3162
		interfaces_sync_setup();
3163
	}
3164
	if ($anyproxyarp == true) {
3165
		interface_proxyarp_configure();
3166
	}
3167
}
3168

    
3169
function interface_ipalias_configure(&$vip) {
3170
	global $config;
3171

    
3172
	$gateway = '';
3173
	if ($vip['mode'] != 'ipalias') {
3174
		return;
3175
	}
3176

    
3177
	$realif = get_real_interface("_vip{$vip['uniqid']}");
3178
	if ($realif != "lo0") {
3179
		$if = convert_real_interface_to_friendly_interface_name($realif);
3180
		if (!isset($config['interfaces'][$if]) ||
3181
		    !isset($config['interfaces'][$if]['enable'])) {
3182
			return;
3183
		}
3184
		if (is_pseudo_interface($realif)) {
3185
			if (is_ipaddrv4($vip['subnet'])) {
3186
				$gateway = get_interface_gateway($if);
3187
			} else {
3188
				$gateway = get_interface_gateway_v6($if);
3189
			}
3190
		}
3191
	}
3192

    
3193
	$af = 'inet';
3194
	if (is_ipaddrv6($vip['subnet'])) {
3195
		$af = 'inet6';
3196
	}
3197
	$iface = $vip['interface'];
3198
	$vhid = '';
3199
	if (substr($vip['interface'], 0, 4) == "_vip") {
3200
		$carpvip = get_configured_vip($vip['interface']);
3201
		$iface = $carpvip['interface'];
3202
		$vhid = "vhid {$carpvip['vhid']}";
3203
	}
3204
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$gateway} {$vhid}");
3205
	unset($iface, $af, $realif, $carpvip, $vhid, $gateway);
3206
}
3207

    
3208
function interface_carp_configure(&$vip, $maintenancemode_only = false) {
3209
	global $config, $g;
3210
	if (isset($config['system']['developerspew'])) {
3211
		$mt = microtime();
3212
		echo "interface_carp_configure() being called $mt\n";
3213
	}
3214

    
3215
	if ($vip['mode'] != "carp") {
3216
		return;
3217
	}
3218

    
3219
	$realif = get_real_interface($vip['interface']);
3220
	if (!does_interface_exist($realif)) {
3221
		file_notice("CARP", sprintf(gettext(
3222
		    "Interface specified for the virtual IP address %s does not exist. Skipping this VIP."),
3223
		    $vip['subnet']), "Firewall: Virtual IP", "");
3224
		return;
3225
	}
3226
	if ($realif != "lo0") {
3227
		if (!isset($config['interfaces'][$vip['interface']]) ||
3228
		    !isset($config['interfaces'][$vip['interface']]['enable'])) {
3229
			return;
3230
		}
3231
	}
3232

    
3233
	$vip_password = $vip['password'];
3234
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3235
	    $vip_password)));
3236
	if ($vip['password'] != "") {
3237
		$password = " pass {$vip_password}";
3238
	}
3239

    
3240
	$advbase = "";
3241
	if (!empty($vip['advbase'])) {
3242
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3243
	}
3244

    
3245
	$carp_maintenancemode = isset(
3246
	    $config["virtualip_carp_maintenancemode"]);
3247
	if ($carp_maintenancemode) {
3248
		$advskew = "advskew 254";
3249
	} else {
3250
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3251
	}
3252

    
3253
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) .
3254
	    " {$advskew} {$advbase} {$password}");
3255

    
3256
	if (!$maintenancemode_only) {
3257
		if (is_ipaddrv4($vip['subnet'])) {
3258
			mwexec("/sbin/ifconfig {$realif} " .
3259
			    escapeshellarg($vip['subnet']) . "/" .
3260
			    escapeshellarg($vip['subnet_bits']) .
3261
			    " alias vhid " . escapeshellarg($vip['vhid']));
3262
		} elseif (is_ipaddrv6($vip['subnet'])) {
3263
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3264
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3265
			    escapeshellarg($vip['subnet_bits']) .
3266
			    " alias vhid " . escapeshellarg($vip['vhid']));
3267
		}
3268
	}
3269

    
3270
	return $realif;
3271
}
3272

    
3273
function interface_wireless_clone($realif, $wlcfg) {
3274
	global $config, $g;
3275
	/*   Check to see if interface has been cloned as of yet.
3276
	 *   If it has not been cloned then go ahead and clone it.
3277
	 */
3278
	$needs_clone = false;
3279
	if (is_array($wlcfg['wireless'])) {
3280
		$wlcfg_mode = $wlcfg['wireless']['mode'];
3281
	} else {
3282
		$wlcfg_mode = $wlcfg['mode'];
3283
	}
3284
	switch ($wlcfg_mode) {
3285
		case "hostap":
3286
			$mode = "wlanmode hostap";
3287
			break;
3288
		case "adhoc":
3289
			$mode = "wlanmode adhoc";
3290
			break;
3291
		default:
3292
			$mode = "";
3293
			break;
3294
	}
3295
	$baseif = interface_get_wireless_base($wlcfg['if']);
3296
	if (does_interface_exist($realif)) {
3297
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
3298
		$ifconfig_str = implode($output);
3299
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
3300
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
3301
			$needs_clone = true;
3302
		}
3303
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
3304
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
3305
			$needs_clone = true;
3306
		}
3307
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
3308
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
3309
			$needs_clone = true;
3310
		}
3311
	} else {
3312
		$needs_clone = true;
3313
	}
3314

    
3315
	if ($needs_clone == true) {
3316
		/* remove previous instance if it exists */
3317
		if (does_interface_exist($realif)) {
3318
			pfSense_interface_destroy($realif);
3319

    
3320
			/* Invalidate cache */
3321
			get_interface_arr(true);
3322
		}
3323

    
3324
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
3325
		// Create the new wlan interface. FreeBSD returns the new interface name.
3326
		// example:  wlan2
3327
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
3328
		if ($ret <> 0) {
3329
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
3330
			return false;
3331
		}
3332
		$newif = trim($out[0]);
3333
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
3334
		pfSense_interface_rename($newif, $realif);
3335
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
3336
	}
3337
	return true;
3338
}
3339

    
3340
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3341
	global $config, $g;
3342

    
3343
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3344
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3345
				 'regdomain', 'regcountry', 'reglocation');
3346

    
3347
	if (!is_interface_wireless($ifcfg['if'])) {
3348
		return;
3349
	}
3350

    
3351
	$baseif = interface_get_wireless_base($ifcfg['if']);
3352

    
3353
	// Sync shared settings for assigned clones
3354
	$iflist = get_configured_interface_list(true);
3355
	foreach ($iflist as $if) {
3356
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
3357
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
3358
				foreach ($shared_settings as $setting) {
3359
					if ($sync_changes) {
3360
						if (isset($ifcfg['wireless'][$setting])) {
3361
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
3362
						} elseif (isset($config['interfaces'][$if]['wireless'][$setting])) {
3363
							unset($config['interfaces'][$if]['wireless'][$setting]);
3364
						}
3365
					} else {
3366
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3367
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
3368
						} elseif (isset($ifcfg['wireless'][$setting])) {
3369
							unset($ifcfg['wireless'][$setting]);
3370
						}
3371
					}
3372
				}
3373
				if (!$sync_changes) {
3374
					break;
3375
				}
3376
			}
3377
		}
3378
	}
3379

    
3380
	// Read or write settings at shared area
3381
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
3382
		foreach ($shared_settings as $setting) {
3383
			if ($sync_changes) {
3384
				if (isset($ifcfg['wireless'][$setting])) {
3385
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
3386
				} elseif (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3387
					unset($config['wireless']['interfaces'][$baseif][$setting]);
3388
				}
3389
			} elseif (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3390
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3391
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
3392
				} elseif (isset($ifcfg['wireless'][$setting])) {
3393
					unset($ifcfg['wireless'][$setting]);
3394
				}
3395
			}
3396
		}
3397
	}
3398

    
3399
	// Sync the mode on the clone creation page with the configured mode on the interface
3400
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3401
		foreach ($config['wireless']['clone'] as &$clone) {
3402
			if ($clone['cloneif'] == $ifcfg['if']) {
3403
				if ($sync_changes) {
3404
					$clone['mode'] = $ifcfg['wireless']['mode'];
3405
				} else {
3406
					$ifcfg['wireless']['mode'] = $clone['mode'];
3407
				}
3408
				break;
3409
			}
3410
		}
3411
		unset($clone);
3412
	}
3413
}
3414

    
3415
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3416
	global $config, $g;
3417

    
3418
	/*    open up a shell script that will be used to output the commands.
3419
	 *    since wireless is changing a lot, these series of commands are fragile
3420
	 *    and will sometimes need to be verified by a operator by executing the command
3421
	 *    and returning the output of the command to the developers for inspection.  please
3422
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3423
	 */
3424

    
3425
	// Remove script file
3426
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3427

    
3428
	// Clone wireless nic if needed.
3429
	interface_wireless_clone($if, $wl);
3430

    
3431
	// Reject inadvertent changes to shared settings in case the interface hasn't been configured.
3432
	interface_sync_wireless_clones($wl, false);
3433

    
3434
	$fd_set = fopen("{$g['tmp_path']}/{$if}_setup.sh", "w");
3435
	fwrite($fd_set, "#!/bin/sh\n");
3436
	fwrite($fd_set, "# {$g['product_label']} wireless configuration script.\n\n");
3437

    
3438
	$wlan_setup_log = fopen("{$g['tmp_path']}/{$if}_setup.log", "w");
3439

    
3440
	/* set values for /path/program */
3441
	if (file_exists("/usr/local/sbin/hostapd")) {
3442
		$hostapd = "/usr/local/sbin/hostapd";
3443
	} else {
3444
		$hostapd = "/usr/sbin/hostapd";
3445
	}
3446
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3447
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3448
	} else {
3449
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3450
	}
3451
	$ifconfig = "/sbin/ifconfig";
3452
	$sysctl = "/sbin/sysctl";
3453
	$sysctl_args = "-q";
3454
	$killall = "/usr/bin/killall";
3455

    
3456
	/* Set all wireless ifconfig variables (split up to get rid of needed checking) */
3457

    
3458
	$wlcmd = array();
3459
	$wl_sysctl = array();
3460
	/* Set a/b/g standard */
3461
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3462
	/* skip mode entirely for "auto" */
3463
	if ($wlcfg['standard'] != "auto") {
3464
		$wlcmd[] = "mode " . escapeshellarg($standard);
3465
	}
3466

    
3467
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3468
	 * to prevent massive packet loss under certain conditions. */
3469
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3470
		$wlcmd[] = "-ampdu";
3471
	}
3472

    
3473
	/* Set ssid */
3474
	if ($wlcfg['ssid']) {
3475
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3476
	}
3477

    
3478
	/* Set 802.11g protection mode */
3479
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3480

    
3481
	/* set wireless channel value */
3482
	if (isset($wlcfg['channel'])) {
3483
		if ($wlcfg['channel'] == "0") {
3484
			$wlcmd[] = "channel any";
3485
		} else {
3486
			if ($wlcfg['channel_width'] != "0") {
3487
				$channel_width = ":" . $wlcfg['channel_width'];
3488
			} else {
3489
				$channel_width = '';
3490
			}
3491
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3492
		}
3493
	}
3494

    
3495
	/* Set antenna diversity value */
3496
	if (isset($wlcfg['diversity'])) {
3497
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3498
	}
3499

    
3500
	/* Set txantenna value */
3501
	if (isset($wlcfg['txantenna'])) {
3502
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3503
	}
3504

    
3505
	/* Set rxantenna value */
3506
	if (isset($wlcfg['rxantenna'])) {
3507
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3508
	}
3509

    
3510
	/* set Distance value */
3511
	if ($wlcfg['distance']) {
3512
		$distance = escapeshellarg($wlcfg['distance']);
3513
	}
3514

    
3515
	/* Set wireless hostap mode */
3516
	if ($wlcfg['mode'] == "hostap") {
3517
		$wlcmd[] = "mediaopt hostap";
3518
	} else {
3519
		$wlcmd[] = "-mediaopt hostap";
3520
	}
3521

    
3522
	/* Set wireless adhoc mode */
3523
	if ($wlcfg['mode'] == "adhoc") {
3524
		$wlcmd[] = "mediaopt adhoc";
3525
	} else {
3526
		$wlcmd[] = "-mediaopt adhoc";
3527
	}
3528

    
3529
	/* Not necessary to set BSS mode as this is default if adhoc and/or hostap is NOT set */
3530

    
3531
	/* handle hide ssid option */
3532
	if (isset($wlcfg['hidessid']['enable'])) {
3533
		$wlcmd[] = "hidessid";
3534
	} else {
3535
		$wlcmd[] = "-hidessid";
3536
	}
3537

    
3538
	/* handle pureg (802.11g) only option */
3539
	if (isset($wlcfg['pureg']['enable'])) {
3540
		$wlcmd[] = "mode 11g pureg";
3541
	} else {
3542
		$wlcmd[] = "-pureg";
3543
	}
3544

    
3545
	/* handle puren (802.11n) only option */
3546
	if (isset($wlcfg['puren']['enable'])) {
3547
		$wlcmd[] = "puren";
3548
	} else {
3549
		$wlcmd[] = "-puren";
3550
	}
3551

    
3552
	/* enable apbridge option */
3553
	if (isset($wlcfg['apbridge']['enable'])) {
3554
		$wlcmd[] = "apbridge";
3555
	} else {
3556
		$wlcmd[] = "-apbridge";
3557
	}
3558

    
3559
	/* handle turbo option */
3560
	if (isset($wlcfg['turbo']['enable'])) {
3561
		$wlcmd[] = "mediaopt turbo";
3562
	} else {
3563
		$wlcmd[] = "-mediaopt turbo";
3564
	}
3565

    
3566
	/* handle txpower setting */
3567
	// or don't. this has issues at the moment.
3568
	/*
3569
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3570
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3571
	}*/
3572

    
3573
	/* handle wme option */
3574
	if (isset($wlcfg['wme']['enable'])) {
3575
		$wlcmd[] = "wme";
3576
	} else {
3577
		$wlcmd[] = "-wme";
3578
	}
3579

    
3580
	/* Enable wpa if it's configured. No WEP support anymore. */
3581
	if (isset($wlcfg['wpa']['enable'])) {
3582
		$wlcmd[] = "authmode wpa wepmode off ";
3583
	} else {
3584
		$wlcmd[] = "authmode open wepmode off ";
3585
	}
3586

    
3587
	kill_hostapd($if);
3588
	mwexec(kill_wpasupplicant("{$if}"));
3589

    
3590
	$wpa_supplicant_file = "{$g['varetc_path']}/wpa_supplicant_{$if}.";
3591
	$hostapd_conf = "{$g['varetc_path']}/hostapd_{$if}.conf";
3592

    
3593
	unlink_if_exists("{$wpa_supplicant_file}*");
3594
	unlink_if_exists($hostapd_conf);
3595

    
3596
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3597

    
3598
	switch ($wlcfg['mode']) {
3599
		case 'bss':
3600
			if (isset($wlcfg['wpa']['enable'])) {
3601
				$wpa .= <<<EOD
3602
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3603
ctrl_interface_group=0
3604
ap_scan=1
3605
#fast_reauth=1
3606
network={
3607
ssid="{$wlcfg['ssid']}"
3608
scan_ssid=1
3609
priority=5
3610
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3611
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3612
group={$wlcfg['wpa']['wpa_pairwise']}
3613

    
3614
EOD;
3615
				if ($wlcfg['wpa']['wpa_key_mgmt'] == 'WPA-EAP') {
3616
					if (($wlcfg['wpa']['wpa_eap_client_mode'] == 'PEAP') ||
3617
					    ($wlcfg['wpa']['wpa_eap_client_mode'] == 'TTLS')) {
3618
						if ($wlcfg['wpa']['wpa_eap_inner_auth'] == 'MSCHAPV2') {
3619
							$wpa .= "phase1=\"peaplabel=0\"\n";
3620
						}
3621
						$wpa .= "phase2=\"auth={$wlcfg['wpa']['wpa_eap_inner_auth']}\"\n";
3622
						$wpa .= "identity=\"{$wlcfg['wpa']['wpa_eap_inner_id']}\"\n";
3623
						$eappass = base64_decode($wlcfg['wpa']['wpa_eap_inner_password']);
3624
						$wpa .= "password=\"{$eappass}\"\n";
3625
					}
3626
					if (strstr($wlcfg['wpa']['wpa_eap_client_mode'], 'TLS')) { 
3627
						$cert = lookup_cert($wlcfg['wpa']['wpa_eap_cert']);
3628
						@file_put_contents($wpa_supplicant_file . "crt", base64_decode($cert['crt']) . "\n" .
3629
						    ca_chain($cert)); 
3630
						@file_put_contents($wpa_supplicant_file . "key", base64_decode($cert['prv'])); 
3631
						@chmod($wpa_supplicant_crt, 0600);
3632
						@chmod($wpa_supplicant_key, 0600);
3633
						$wpa .= "client_cert=\"{$wpa_supplicant_crt}\"\n";
3634
						$wpa .= "private_key=\"{$wpa_supplicant_key}\"\n";
3635
					}
3636
					$ca = lookup_ca($wlcfg['wpa']['wpa_eap_ca']);
3637
					@file_put_contents($wpa_supplicant_file . "ca", base64_decode($ca['crt']) . "\n" .
3638
					    ca_chain($ca)); 
3639
					$wpa .= "ca_cert=\"{$wpa_supplicant_ca}\"\n";
3640
					$wpa .= "eap={$wlcfg['wpa']['wpa_eap_client_mode']}\n";
3641
				} else {
3642
					$wpa .= "psk=\"{$wlcfg['wpa']['passphrase']}\"\n";
3643
				}
3644
				$wpa .= "}\n";
3645

    
3646
				@file_put_contents($wpa_supplicant_file . "conf", $wpa);
3647
				unset($wpa);
3648
			}
3649
			break;
3650
		case 'hostap':
3651
			if (!empty($wlcfg['wpa']['passphrase'])) {
3652
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3653
			} else {
3654
				$wpa_passphrase = "";
3655
			}
3656
			if (isset($wlcfg['wpa']['enable'])) {
3657
				$wpa .= <<<EOD
3658
interface={$if}
3659
driver=bsd
3660
logger_syslog=-1
3661
logger_syslog_level=0
3662
logger_stdout=-1
3663
logger_stdout_level=0
3664
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3665
ctrl_interface={$g['varrun_path']}/hostapd
3666
ctrl_interface_group=wheel
3667
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3668
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3669
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3670
ssid={$wlcfg['ssid']}
3671
debug={$wlcfg['wpa']['debug_mode']}
3672
wpa={$wlcfg['wpa']['wpa_mode']}
3673
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3674
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3675
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3676
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3677
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3678
{$wpa_passphrase}
3679

    
3680
EOD;
3681

    
3682
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3683
					$wpa .= <<<EOD
3684
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3685
rsn_preauth=1
3686
rsn_preauth_interfaces={$if}
3687

    
3688
EOD;
3689
				}
3690
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3691
					$wpa .= "ieee8021x=1\n";
3692

    
3693
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3694
						$auth_server_port = "1812";
3695
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3696
							$auth_server_port = intval($wlcfg['auth_server_port']);
3697
						}
3698
						$wpa .= <<<EOD
3699

    
3700
auth_server_addr={$wlcfg['auth_server_addr']}
3701
auth_server_port={$auth_server_port}
3702
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3703

    
3704
EOD;
3705
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3706
							$auth_server_port2 = "1812";
3707
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3708
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3709
							}
3710

    
3711
							$wpa .= <<<EOD
3712
auth_server_addr={$wlcfg['auth_server_addr2']}
3713
auth_server_port={$auth_server_port2}
3714
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3715

    
3716
EOD;
3717
						}
3718
					}
3719
				}
3720

    
3721
				@file_put_contents($hostapd_conf, $wpa);
3722
				unset($wpa);
3723
			}
3724
			break;
3725
	}
3726

    
3727
	/*
3728
	 *    all variables are set, lets start up everything
3729
	 */
3730

    
3731
	$baseif = interface_get_wireless_base($if);
3732
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3733
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3734

    
3735
	/* set sysctls for the wireless interface */
3736
	if (!empty($wl_sysctl)) {
3737
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3738
		foreach ($wl_sysctl as $wl_sysctl_line) {
3739
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3740
		}
3741
	}
3742

    
3743
	/* set ack timers according to users preference (if he/she has any) */
3744
	if ($distance) {
3745
		fwrite($fd_set, "# Enable ATH distance settings\n");
3746
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3747
	}
3748

    
3749
	if (isset($wlcfg['wpa']['enable'])) {
3750
		if ($wlcfg['mode'] == "bss") {
3751
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3752
		}
3753
		if ($wlcfg['mode'] == "hostap") {
3754
			/* add line to script to restore old mac to make hostapd happy */
3755
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3756
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3757
				$if_curmac = get_interface_mac($if);
3758
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3759
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3760
						" link " . escapeshellarg($if_oldmac) . "\n");
3761
				}
3762
			}
3763

    
3764
			fwrite($fd_set, "{$hostapd} -B -P {$g['varrun_path']}/hostapd_{$if}.pid {$g['varetc_path']}/hostapd_{$if}.conf\n");
3765

    
3766
			/* add line to script to restore spoofed mac after running hostapd */
3767
			if ($wl['spoofmac']) {
3768
				$if_curmac = get_interface_mac($if);
3769
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3770
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3771
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3772
				}
3773
			}
3774
		}
3775
	}
3776

    
3777
	fclose($fd_set);
3778

    
3779
	/* Making sure regulatory settings have actually changed
3780
	 * before applying, because changing them requires bringing
3781
	 * down all wireless networks on the interface. */
3782
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3783
	$ifconfig_str = implode($output);
3784
	unset($output);
3785
	$reg_changing = false;
3786

    
3787
	/* special case for the debug country code */
3788
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3789
		$reg_changing = true;
3790
	} elseif ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3791
		$reg_changing = true;
3792
	} elseif ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3793
		$reg_changing = true;
3794
	} elseif ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3795
		$reg_changing = true;
3796
	} elseif ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3797
		$reg_changing = true;
3798
	}
3799

    
3800
	if ($reg_changing) {
3801
		/* set regulatory domain */
3802
		if ($wlcfg['regdomain']) {
3803
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3804
		}
3805

    
3806
		/* set country */
3807
		if ($wlcfg['regcountry']) {
3808
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3809
		}
3810

    
3811
		/* set location */
3812
		if ($wlcfg['reglocation']) {
3813
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3814
		}
3815

    
3816
		$wlregcmd_args = implode(" ", $wlregcmd);
3817

    
3818
		/* build a complete list of the wireless clones for this interface */
3819
		$clone_list = array();
3820
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3821
			$clone_list[] = interface_get_wireless_clone($baseif);
3822
		}
3823
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3824
			foreach ($config['wireless']['clone'] as $clone) {
3825
				if ($clone['if'] == $baseif) {
3826
					$clone_list[] = $clone['cloneif'];
3827
				}
3828
			}
3829
		}
3830

    
3831
		/* find which clones are up and bring them down */
3832
		$clones_up = array();
3833
		foreach ($clone_list as $clone_if) {
3834
			$clone_status = pfSense_get_interface_addresses($clone_if);
3835
			if ($clone_status['status'] == 'up') {
3836
				$clones_up[] = $clone_if;
3837
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3838
			}
3839
		}
3840

    
3841
		/* apply the regulatory settings */
3842
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3843
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3844

    
3845
		/* bring the clones back up that were previously up */
3846
		foreach ($clones_up as $clone_if) {
3847
			interfaces_bring_up($clone_if);
3848

    
3849
			/*
3850
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3851
			 * is in infrastructure mode, and WPA is enabled.
3852
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3853
			 */
3854
			if ($clone_if != $if) {
3855
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3856
				if ((!empty($friendly_if)) &&
3857
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3858
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3859
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3860
				}
3861
			}
3862
		}
3863
	}
3864

    
3865
	/* The mode must be specified in a separate command before ifconfig
3866
	 * will allow the mode and channel at the same time in the next.
3867
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3868
	 */
3869
	if ($wlcfg['mode'] == "hostap") {
3870
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3871
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3872
	}
3873

    
3874
	/* configure wireless */
3875
	$wlcmd_args = implode(" ", $wlcmd);
3876
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args);
3877
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3878
	/* Bring the interface up only after setting up all the other parameters. */
3879
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up");
3880
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3881
	fclose($wlan_setup_log);
3882

    
3883
	unset($wlcmd_args, $wlcmd);
3884

    
3885

    
3886
	sleep(1);
3887
	/* execute hostapd and wpa_supplicant if required in shell */
3888
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3889

    
3890
	return 0;
3891

    
3892
}
3893

    
3894
function kill_hostapd($interface) {
3895
	global $g;
3896

    
3897
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3898
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3899
	}
3900
}
3901

    
3902
function kill_wpasupplicant($interface) {
3903
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3904
}
3905

    
3906
function find_dhclient_process($interface) {
3907
	if ($interface) {
3908
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3909
	} else {
3910
		$pid = 0;
3911
	}
3912

    
3913
	return intval($pid);
3914
}
3915

    
3916
function kill_dhclient_process($interface) {
3917
	if (empty($interface) || !does_interface_exist($interface)) {
3918
		return;
3919
	}
3920

    
3921
	$i = 0;
3922
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3923
		/* 3rd time make it die for sure */
3924
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3925
		posix_kill($pid, $sig);
3926
		sleep(1);
3927
		$i++;
3928
	}
3929
	unset($i);
3930
}
3931

    
3932
function find_dhcp6c_process($interface) {
3933
	global $g;
3934

    
3935
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3936
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3937
	} else {
3938
		return(false);
3939
	}
3940

    
3941
	return intval($pid);
3942
}
3943

    
3944
function kill_dhcp6client_process($interface, $force, $release = false) {
3945
	global $g;
3946

    
3947
	$i = 0;
3948

    
3949
	/*
3950
	Beware of the following: Reason, the interface may be down, but
3951
	dhcp6c may still be running, it just complains it cannot send
3952
	and carries on. Commented out as will stop the call to kill.
3953

    
3954
	if (empty($interface) || !does_interface_exist($interface)) {
3955
		return;
3956
	}
3957
	*/
3958

    
3959
	/*********** Notes on signals for dhcp6c and this function *************
3960

    
3961
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3962
	a release and waiting for the response that never comes.
3963
	So we need to tell it that the interface is down and to just die quickly
3964
	otherwise a new client may launch and we have duplicate proceses.
3965
	In this case use SIGUSR1.
3966

    
3967
	If we want to exit normally obeying the no release flag then use SIGTERM.
3968
	If we want to exit with a release overiding the no release flag then
3969
	use SIGUSR2.
3970

    
3971
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3972
	exit quickly without sending release signals.
3973

    
3974
	If $Force is set to false and $release is also set to false dhcp6c will
3975
	follow the no-release flag.
3976

    
3977
	If $Force is set to false and $release is true then dhcp6c will send a
3978
	release regardless of the no-release flag.
3979
	***********************************************************************/
3980

    
3981
	if ($force == true) {
3982
		$psig=SIGUSR1;
3983
	} elseif ($release == false) {
3984
		$psig=SIGTERM;
3985
	} else {
3986
		$psig=SIGUSR2;
3987
	}
3988

    
3989
	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
3990
		/* 3rd time make it die for sure */
3991
		$sig = ($i == 2 ? SIGKILL : $psig);
3992
		posix_kill($pid, $sig);
3993
		sleep(1);
3994
		$i++;
3995
	}
3996
	/* Clear the RTSOLD script created lock & tidy up */
3997
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
3998
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
3999
}
4000
function reset_dhcp6client_process($interface) {
4001

    
4002
	$pid = find_dhcp6c_process($interface);
4003

    
4004
	if($pid != 0) {
4005
		posix_kill($pid, SIGHUP);
4006
	}
4007
}
4008

    
4009
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
4010
	global $g;
4011

    
4012
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4013
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4014

    
4015
	/*
4016
	 * Only run this if the lock does not exist. In theory the lock being
4017
	 * there in this mode means the user has selected dhcp6withoutRA while
4018
	 * a session is active in the other mode.
4019
	 *
4020
	 * It should not happen as the process should have been killed and the
4021
	 * lock deleted.
4022
	 */
4023

    
4024
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
4025
		kill_dhcp6client_process($interface, true);
4026
		/* Lock it to avoid multiple runs */
4027
		touch("/tmp/dhcp6c_{$interface}_lock");
4028
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
4029
		    "{$noreleaseOption} " .
4030
		    "-c {$g['varetc_path']}/dhcp6c_{$interface_name}.conf " .
4031
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
4032
		    $interface);
4033
		log_error(sprintf(gettext(
4034
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
4035
		    $interface));
4036
	}
4037
}
4038

    
4039
function interface_virtual_create($interface) {
4040
	global $config;
4041

    
4042
	if (interface_is_vlan($interface) != NULL) {
4043
		interface_vlan_configure(interface_is_vlan($interface));
4044
	} elseif (substr($interface, 0, 3) == "gre") {
4045
		interfaces_tunnel_configure(0, $interface, 'gre');
4046
	} elseif (substr($interface, 0, 3) == "gif") {
4047
		interfaces_tunnel_configure(0, $interface, 'gif');
4048
	} elseif (substr($interface, 0, 5) == "ovpns") {
4049
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
4050
			foreach ($config['openvpn']['openvpn-server'] as $server) {
4051
				if ($interface == "ovpns{$server['vpnid']}") {
4052
					if (!function_exists('openvpn_resync')) {
4053
						require_once('openvpn.inc');
4054
					}
4055
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
4056
					openvpn_resync('server', $server);
4057
				}
4058
			}
4059
			unset($server);
4060
		}
4061
	} elseif (substr($interface, 0, 5) == "ovpnc") {
4062
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
4063
			foreach ($config['openvpn']['openvpn-client'] as $client) {
4064
				if ($interface == "ovpnc{$client['vpnid']}") {
4065
					if (!function_exists('openvpn_resync')) {
4066
						require_once('openvpn.inc');
4067
					}
4068
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
4069
					openvpn_resync('client', $client);
4070
				}
4071
			}
4072
			unset($client);
4073
		}
4074
	} elseif (substr($interface, 0, 5) == "ipsec") {
4075
		if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
4076
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
4077
				if ($ph1ent['disabled']) {
4078
					continue;
4079
				}
4080
				if ($interface == "ipsec{$ph1ent['ikeid']}") {
4081
					interface_ipsec_vti_configure($ph1ent);
4082
				}
4083
			}
4084
		}
4085
	} elseif (substr($interface, 0, 4) == "lagg") {
4086
		interfaces_lagg_configure($interface);
4087
	} elseif (substr($interface, 0, 6) == "bridge") {
4088
		interfaces_bridge_configure(0, $interface);
4089
	}
4090
}
4091

    
4092
function interface_vlan_mtu_configured($iface) {
4093
	global $config;
4094

    
4095
	$mtu = 0;
4096
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
4097
		foreach ($config['vlans']['vlan'] as $vlan) {
4098

    
4099
			if ($vlan['vlanif'] != $iface)
4100
				continue;
4101

    
4102
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4103
			$parentinf = convert_real_interface_to_friendly_interface_name($vlan['if']);
4104
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
4105
				/* VLAN MTU */
4106
				$mtu = $config['interfaces'][$assignedport]['mtu'];
4107
			} elseif (!empty($config['interfaces'][$parentinf]['mtu'])) {
4108
				/* Parent MTU */
4109
				$mtu = $config['interfaces'][$parentinf]['mtu'];
4110
			}
4111
		}
4112
	}
4113

    
4114
	return $mtu;
4115
}
4116

    
4117
function interface_mtu_wanted_for_pppoe($realif) {
4118
	global $config;
4119

    
4120
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
4121
		return 0;
4122

    
4123
	$mtu = 0;
4124
	foreach ($config['ppps']['ppp'] as $ppp) {
4125
		if ($ppp['type'] != "pppoe") {
4126
			continue;
4127
		}
4128

    
4129
		$mtus = array();
4130
		if (!empty($ppp['mtu'])) {
4131
			$mtus = explode(',', $ppp['mtu']);
4132
		}
4133
		$ports = explode(',', $ppp['ports']);
4134

    
4135
		foreach ($ports as $pid => $port) {
4136
			$parentifa = get_parent_interface($port);
4137
			$parentif = $parentifa[0];
4138
			if ($parentif != $realif)
4139
				continue;
4140

    
4141
			// there is an MTU configured on the port in question
4142
			if (!empty($mtus[$pid])) {
4143
				$mtu = intval($mtus[$pid]) + 8;
4144
			// or use the MTU configured on the interface ...
4145
			} elseif (is_array($config['interfaces'])) {
4146
				foreach ($config['interfaces'] as $interface) {
4147
					if ($interface['if'] == $ppp['if'] &&
4148
					    !empty($interface['mtu'])) {
4149
						$mtu = intval($interface['mtu']) + 8;
4150
						break;
4151
					}
4152
				}
4153
			}
4154
		}
4155
	}
4156

    
4157
	return $mtu;
4158
}
4159

    
4160
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
4161
	global $config, $g;
4162
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
4163
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
4164

    
4165
	$wancfg = $config['interfaces'][$interface];
4166

    
4167
	if (!isset($wancfg['enable'])) {
4168
		return;
4169
	}
4170

    
4171
	$realif = get_real_interface($interface);
4172
	$realhwif_array = get_parent_interface($interface);
4173
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
4174
	$realhwif = $realhwif_array[0];
4175

    
4176
	$mac_if_cfg = $wancfg;
4177
	if (interface_is_vlan($realif)) {
4178
		$mac_if = convert_real_interface_to_friendly_interface_name(
4179
		    $realhwif);
4180
		if (is_array($config['interfaces'][$mac_if])) {
4181
			$mac_if_cfg = $config['interfaces'][$mac_if];
4182
		} else {
4183
			$mac_if = $interface;
4184
		}
4185
	}
4186

    
4187
	if (!platform_booting() && (substr($realif, 0, 4) != "ovpn") && (substr($realif, 0, 5) != "ipsec")) {
4188
		/* remove all IPv4 and IPv6 addresses */
4189
		$tmpifaces = pfSense_getall_interface_addresses($realif);
4190
		if (is_array($tmpifaces)) {
4191
			foreach ($tmpifaces as $tmpiface) {
4192
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
4193
					if (!is_linklocal($tmpiface)) {
4194
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
4195
					}
4196
				} elseif (strstr($tmpiface, "fe80::1:1")) {
4197
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 fe80::1:1 -alias");
4198
				} else {
4199
					if (is_subnetv4($tmpiface)) {
4200
						$tmpip = explode('/', $tmpiface);
4201
						$tmpip = $tmpip[0];
4202
					} else {
4203
						$tmpip = $tmpiface;
4204
					}
4205
					pfSense_interface_deladdress($realif, $tmpip);
4206
				}
4207
			}
4208
		}
4209

    
4210
		/* only bring down the interface when both v4 and v6 are set to NONE */
4211
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
4212
			interface_bring_down($interface);
4213
		}
4214
	}
4215

    
4216
	$interface_to_check = $realif;
4217
	if (interface_isppp_type($interface)) {
4218
		$interface_to_check = $realhwif;
4219
	}
4220

    
4221
	/* Need to check that the interface exists or not in the case where its coming back from disabled state see #3270 */
4222
	if (!platform_booting() && (in_array(substr($realif, 0, 3), array("gre", "gif", "ips")) || !does_interface_exist($interface_to_check))) {
4223
		interface_virtual_create($interface_to_check);
4224
	}
4225

    
4226
	/* Disable Accepting router advertisements unless specifically requested */
4227
	if ($g['debug']) {
4228
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
4229
	}
4230
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
4231
	{
4232
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
4233
	}
4234
	/* wireless configuration? */
4235
	if (is_array($wancfg['wireless']) && !$linkupevent) {
4236
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
4237
	}
4238

    
4239
	$current_mac = get_interface_mac($realhwif);
4240
	$vendor_mac = get_interface_vendor_mac($realhwif);
4241

    
4242
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
4243
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
4244

    
4245
		interface_set_macaddr($realhwif, $mac_addr);
4246
	} else {
4247
		/*
4248
		 * this is not a valid mac address.  generate a
4249
		 * temporary mac address so the machine can get online.
4250
		 */
4251
		echo gettext("Generating new MAC address.");
4252
		$random_mac = generate_random_mac_address();
4253
		interface_set_macaddr($realhwif, $random_mac);
4254
		$config['interfaces'][$mac_if]['spoofmac'] = $random_mac;
4255
		write_config(sprintf(gettext('The invalid MAC address ' .
4256
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
4257
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
4258
		file_notice("MAC Address altered", sprintf(gettext('The ' .
4259
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
4260
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
4261
		    $random_mac), "Interfaces");
4262
	}
4263

    
4264
	/* media */
4265
	if ($wancfg['media'] || $wancfg['mediaopt']) {
4266
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
4267
		if ($wancfg['media']) {
4268
			$cmd .= " media " . escapeshellarg($wancfg['media']);
4269
		}
4270
		if ($wancfg['mediaopt']) {
4271
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
4272
		}
4273
		mwexec($cmd);
4274
	}
4275

    
4276
	/* Apply hw offloading policies as configured */
4277
	enable_hardware_offloading($interface);
4278

    
4279
	/* invalidate interface/ip/sn cache */
4280
	get_interface_arr(true);
4281
	unset($interface_ip_arr_cache[$realif]);
4282
	unset($interface_sn_arr_cache[$realif]);
4283
	unset($interface_ipv6_arr_cache[$realif]);
4284
	unset($interface_snv6_arr_cache[$realif]);
4285

    
4286
	$tunnelif = substr($realif, 0, 3);
4287

    
4288
	$mtuif = $realif;
4289
	$mtuhwif = $realhwif;
4290

    
4291
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
4292
	if (interface_isppp_type($interface)) {
4293
		$mtuif = $realhwif;
4294
		$mtuhwif_array = get_parent_interface($mtuif);
4295
		$mtuhwif = $mtuhwif_array[0];
4296
	}
4297

    
4298
	$wantedmtu = 0;
4299
	if (is_array($config['interfaces'])) {
4300
		foreach ($config['interfaces'] as $tmpinterface) {
4301
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
4302
				$wantedmtu = $tmpinterface['mtu'];
4303
				break;
4304
			}
4305
		}
4306
	}
4307

    
4308
	/* MTU is not specified for interface, try the pppoe settings. */
4309
	if ($wantedmtu == 0) {
4310
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
4311
	}
4312
	if (($wantedmtu == 0) && (interface_is_vlan($mtuif) != NULL) && interface_isppp_type($interface)) {
4313
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
4314
	}
4315
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gre')) {
4316
		/* set MTU to 1400 for GRE over IPsec */
4317
		if (is_greipsec($mtuif)) {
4318
			$wantedmtu = 1400;
4319
		} else {
4320
			$wantedmtu = 1476;
4321
		}
4322
	}
4323
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gif')) {
4324
		$wantedmtu = 1280;
4325
	}
4326

    
4327
	/* Set the MTU to 1500 if no explicit MTU configured. */
4328
	if ($wantedmtu == 0) {
4329
		$wantedmtu = 1500; /* Default */
4330
	}
4331

    
4332
	if (interface_is_vlan($mtuif) != NULL) {
4333
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4334
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
4335
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
4336
			if ($wancfg['mtu'] > $parentmtu) {
4337
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4338
			}
4339
		}
4340

    
4341
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4342

    
4343
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4344
			$configuredmtu = $parentmtu;
4345
		if ($configuredmtu != 0)
4346
			$mtu = $configuredmtu;
4347
		else
4348
			$mtu = $wantedmtu;
4349

    
4350
		/* Set the parent MTU. */
4351
		if (get_interface_mtu($mtuhwif) < $mtu)
4352
			set_interface_mtu($mtuhwif, $mtu);
4353
		/* Set the VLAN MTU. */
4354
		if (get_interface_mtu($mtuif) != $mtu)
4355
			set_interface_mtu($mtuif, $mtu);
4356
	} elseif (substr($mtuif, 0, 4) == 'lagg') {
4357
		/* LAGG interface must be destroyed and re-created to change MTU */
4358
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4359
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
4360
				foreach ($config['laggs']['lagg'] as $lagg) {
4361
					if ($lagg['laggif'] == $mtuif) {
4362
						interface_lagg_configure($lagg);
4363
						break;
4364
					}
4365
				}
4366
			}
4367
		}
4368
	} else {
4369
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4370
			pfSense_interface_mtu($mtuif, $wantedmtu);
4371
			set_ipv6routes_mtu($mtuif, $wantedmtu);
4372
		}
4373
	}
4374
	/* XXX: What about gre/gif/.. ? */
4375

    
4376
	if (does_interface_exist($wancfg['if'])) {
4377
		interfaces_bring_up($wancfg['if']);
4378
	}
4379

    
4380
	switch ($wancfg['ipaddr']) {
4381
		case 'dhcp':
4382
			interface_dhcp_configure($interface);
4383
			break;
4384
		case 'pppoe':
4385
		case 'l2tp':
4386
		case 'pptp':
4387
		case 'ppp':
4388
			interface_ppps_configure($interface);
4389
			break;
4390
		default:
4391
			/* XXX: Kludge for now related to #3280 */
4392
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
4393
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
4394
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
4395
				}
4396
			}
4397
			break;
4398
	}
4399

    
4400
	switch ($wancfg['ipaddrv6']) {
4401
		case 'slaac':
4402
		case 'dhcp6':
4403
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
4404
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
4405
			// handles all non-PPP connections with 'dhcp6usev4iface' set
4406
			/* Remove the check file. Should not be there but just in case */
4407
			unlink_if_exists("/tmp/{$wanif}_dhcp6_complete");
4408
			log_error(gettext("calling interface_dhcpv6_configure."));
4409
			if ((($wancfg['ipaddrv6'] == 'dhcp6') && !isset($wancfg['dhcp6usev4iface'])) ||
4410
			    (($wancfg['ipaddrv6'] == 'slaac') && !isset($wancfg['slaacusev4iface'])) ||
4411
			    !interface_isppp_type($interface)) {
4412
				interface_dhcpv6_configure($interface, $wancfg);
4413
			}
4414
			break;
4415
		case '6rd':
4416
			interface_6rd_configure($interface, $wancfg);
4417
			break;
4418
		case '6to4':
4419
			interface_6to4_configure($interface, $wancfg);
4420
			break;
4421
		case 'track6':
4422
			interface_track6_configure($interface, $wancfg, $linkupevent);
4423
			break;
4424
		default:
4425
			/* XXX: Kludge for now related to #3280 */
4426
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
4427
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
4428
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
4429
					// FIXME: Add IPv6 Support to the pfSense module
4430
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
4431
				}
4432
			}
4433
			break;
4434
	}
4435

    
4436
	interface_netgraph_needed($interface);
4437

    
4438
	if (!platform_booting()) {
4439
		link_interface_to_vips($interface, "update");
4440

    
4441
		if ($tunnelif != 'gre') {
4442
			unset($gre);
4443
			$gre = link_interface_to_tunnelif($interface, 'gre');
4444
			if (!empty($gre)) {
4445
				array_walk($gre, 'interface_gre_configure');
4446
			}
4447
		}
4448

    
4449
		if ($tunnelif != 'gif') {
4450
			unset($gif);
4451
			$gif = link_interface_to_tunnelif($interface, 'gif');
4452
			if (!empty($gif)) {
4453
				array_walk($gif, 'interface_gif_configure');
4454
			}
4455
		}
4456

    
4457
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4458
			unset($bridgetmp);
4459
			$bridgetmp = link_interface_to_bridge($interface);
4460
			if (!empty($bridgetmp)) {
4461
				interface_bridge_add_member($bridgetmp, $realif);
4462
			}
4463
		}
4464

    
4465
		$grouptmp = link_interface_to_group($interface);
4466
		if (!empty($grouptmp)) {
4467
			array_walk($grouptmp, 'interface_group_add_member');
4468
		}
4469

    
4470
		if ($interface == "lan") {
4471
			/* make new hosts file */
4472
			system_hosts_generate();
4473
		}
4474

    
4475
		if ($reloadall == true) {
4476

    
4477
			/* reconfigure static routes (kernel may have deleted them) */
4478
			system_routing_configure($interface);
4479

    
4480
			/* reload ipsec tunnels */
4481
			send_event("service reload ipsecdns");
4482

    
4483
			if (isset($config['dnsmasq']['enable'])) {
4484
				services_dnsmasq_configure();
4485
			}
4486

    
4487
			if (isset($config['unbound']['enable'])) {
4488
				services_unbound_configure();
4489
			}
4490

    
4491
			/* update dyndns */
4492
			send_event("service reload dyndns {$interface}");
4493

    
4494
			/* reload captive portal */
4495
			if (!function_exists('captiveportal_init_rules_byinterface')) {
4496
				require_once('captiveportal.inc');
4497
			}
4498
			captiveportal_init_rules_byinterface($interface);
4499
		}
4500
	}
4501

    
4502
	if (!empty($wancfg['descr'])) {
4503
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4504
	};
4505

    
4506
	interfaces_staticarp_configure($interface);
4507
	return 0;
4508
}
4509

    
4510
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4511
	global $config, $g;
4512

    
4513
	if (!is_array($wancfg)) {
4514
		return;
4515
	}
4516

    
4517
	if (!isset($wancfg['enable'])) {
4518
		return;
4519
	}
4520

    
4521
	/* If the interface is not configured via another, exit */
4522
	if (empty($wancfg['track6-interface'])) {
4523
		return;
4524
	}
4525

    
4526
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4527
	$realif = get_real_interface($interface);
4528
	$linklocal = find_interface_ipv6_ll($realif, true);
4529
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4530
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4531
	}
4532

    
4533
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4534
	if (!isset($trackcfg['enable'])) {
4535
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4536
		return;
4537
	}
4538

    
4539
	switch ($trackcfg['ipaddrv6']) {
4540
		case "6to4":
4541
			if ($g['debug']) {
4542
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4543
			}
4544
			interface_track6_6to4_configure($interface, $wancfg);
4545
			break;
4546
		case "6rd":
4547
			if ($g['debug']) {
4548
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4549
			}
4550
			interface_track6_6rd_configure($interface, $wancfg);
4551
			break;
4552
		case "dhcp6":
4553
			if ($linkupevent == true) {
4554
				/*
4555
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4556
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4557
				 *
4558
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4559
				 */
4560
				$parentrealif = get_real_interface($wancfg['track6-interface']);
4561
				$pidv6 = find_dhcp6c_process($parentrealif);
4562
				if ($pidv6) {
4563
					posix_kill($pidv6, SIGHUP);
4564
				}
4565
			}
4566
			break;
4567
	}
4568

    
4569
	if ($linkupevent == false && !platform_booting()) {
4570
		if (!function_exists('services_dhcpd_configure')) {
4571
			require_once("services.inc");
4572
		}
4573

    
4574
		/* restart dns servers (defering dhcpd reload) */
4575
		if (isset($config['unbound']['enable'])) {
4576
			services_unbound_configure(false);
4577
		}
4578
		if (isset($config['dnsmasq']['enable'])) {
4579
			services_dnsmasq_configure(false);
4580
		}
4581

    
4582
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4583
		services_dhcpd_configure("inet6");
4584
	}
4585

    
4586
	return 0;
4587
}
4588

    
4589
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4590
	global $config, $g;
4591
	global $interface_ipv6_arr_cache;
4592
	global $interface_snv6_arr_cache;
4593

    
4594
	if (!is_array($lancfg)) {
4595
		return;
4596
	}
4597

    
4598
	/* If the interface is not configured via another, exit */
4599
	if (empty($lancfg['track6-interface'])) {
4600
		return;
4601
	}
4602

    
4603
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4604
	if (empty($wancfg)) {
4605
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4606
		return;
4607
	}
4608

    
4609
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4610
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4611
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not valid, not configuring 6RD tunnel'), $ip4address, $lancfg['track6-interface']));
4612
		return;
4613
	}
4614
	$hexwanv4 = return_hex_ipv4($ip4address);
4615

    
4616
	/* create the long prefix notation for math, save the prefix length */
4617
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4618
	$rd6prefixlen = $rd6prefix[1];
4619
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4620

    
4621
	/* binary presentation of the prefix for all 128 bits. */
4622
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4623

    
4624
	/* just save the left prefix length bits */
4625
	$rd6lanbin = substr($rd6lanbin, 0, $rd6prefixlen);
4626
	/* add the v4 address, offset n bits from the left */
4627
	$rd6lanbin .= substr(sprintf("%032b", hexdec($hexwanv4)), (0 + $wancfg['prefix-6rd-v4plen']), 32);
4628

    
4629
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4630
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4631
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4632
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4633
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4634
	/* fill the rest out with zeros */
4635
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4636

    
4637
	/* convert the 128 bits for the lan address back into a valid IPv6 address */
4638
	$rd6lan = convert_128bit_to_ipv6($rd6lanbin) ."1";
4639

    
4640
	$lanif = get_real_interface($interface);
4641
	$oip = find_interface_ipv6($lanif);
4642
	if (is_ipaddrv6($oip)) {
4643
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4644
	}
4645
	unset($interface_ipv6_arr_cache[$lanif]);
4646
	unset($interface_snv6_arr_cache[$lanif]);
4647
	log_error(sprintf(gettext('rd6 %1$s with ipv6 address %2$s based on %3$s ipv4 %4$s'), $interface, $rd6lan, $lancfg['track6-interface'], $ip4address));
4648
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4649

    
4650
	return 0;
4651
}
4652

    
4653
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4654
	global $config, $g;
4655
	global $interface_ipv6_arr_cache;
4656
	global $interface_snv6_arr_cache;
4657

    
4658
	if (!is_array($lancfg)) {
4659
		return;
4660
	}
4661

    
4662
	/* If the interface is not configured via another, exit */
4663
	if (empty($lancfg['track6-interface'])) {
4664
		return;
4665
	}
4666

    
4667
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4668
	if (empty($wancfg)) {
4669
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4670
		return;
4671
	}
4672

    
4673
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4674
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4675
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $lancfg['track6-interface']));
4676
		return;
4677
	}
4678
	$hexwanv4 = return_hex_ipv4($ip4address);
4679

    
4680
	/* create the long prefix notation for math, save the prefix length */
4681
	$sixto4prefix = "2002::";
4682
	$sixto4prefixlen = 16;
4683
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4684

    
4685
	/* binary presentation of the prefix for all 128 bits. */
4686
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4687

    
4688
	/* just save the left prefix length bits */
4689
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4690
	/* add the v4 address */
4691
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4692
	/* add the custom prefix id */
4693
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4694
	/* fill the rest out with zeros */
4695
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4696

    
4697
	/* convert the 128 bits for the lan address back into a valid IPv6 address */
4698
	$sixto4lan = convert_128bit_to_ipv6($sixto4lanbin) ."1";
4699

    
4700
	$lanif = get_real_interface($interface);
4701
	$oip = find_interface_ipv6($lanif);
4702
	if (is_ipaddrv6($oip)) {
4703
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4704
	}
4705
	unset($interface_ipv6_arr_cache[$lanif]);
4706
	unset($interface_snv6_arr_cache[$lanif]);
4707
	log_error(sprintf(gettext('sixto4 %1$s with ipv6 address %2$s based on %3$s ipv4 %4$s'), $interface, $sixto4lan, $lancfg['track6-interface'], $ip4address));
4708
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4709

    
4710
	return 0;
4711
}
4712

    
4713
function interface_6rd_configure($interface = "wan", $wancfg) {
4714
	global $config, $g;
4715

    
4716
	/* because this is a tunnel interface we can only function
4717
	 *	with a public IPv4 address on the interface */
4718

    
4719
	if (!is_array($wancfg)) {
4720
		return;
4721
	}
4722

    
4723
	if (!is_module_loaded('if_stf.ko')) {
4724
		mwexec('/sbin/kldload if_stf.ko');
4725
	}
4726

    
4727
	$wanif = get_real_interface($interface);
4728
	$ip4address = find_interface_ip($wanif);
4729
	if (!is_ipaddrv4($ip4address)) {
4730
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4731
		return false;
4732
	}
4733
	$hexwanv4 = return_hex_ipv4($ip4address);
4734

    
4735
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4736
		$wancfg['prefix-6rd-v4plen'] = 0;
4737
	}
4738

    
4739
	/* create the long prefix notation for math, save the prefix length */
4740
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4741
	$rd6prefixlen = $rd6prefix[1];
4742
	$brgw = explode('.', $wancfg['gateway-6rd']);
4743
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4744
	$rd6brgw .= str_pad(decbin($brgw[0]), 8, '0', STR_PAD_LEFT) . str_pad(decbin($brgw[1]), 8, '0', STR_PAD_LEFT) . str_pad(decbin($brgw[2]), 8, '0', STR_PAD_LEFT) . str_pad(decbin($brgw[3]), 8, '0', STR_PAD_LEFT);
4745
	if (strlen($rd6brgw) < 128) {
4746
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4747
	}
4748
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4749
	unset($brgw);
4750
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4751

    
4752
	/* binary presentation of the prefix for all 128 bits. */
4753
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4754

    
4755
	/* just save the left prefix length bits */
4756
	$rd6prefixbin = substr($rd6prefixbin, 0, $rd6prefixlen);
4757
	/* if the prefix length is not 32 bits we need to shave bits off from the left of the v4 address. */
4758
	$rd6prefixbin .= substr(sprintf("%032b", hexdec($hexwanv4)), $wancfg['prefix-6rd-v4plen'], 32);
4759
	/* fill out the rest with 0's */
4760
	$rd6prefixbin = str_pad($rd6prefixbin, 128, "0", STR_PAD_RIGHT);
4761

    
4762
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4763
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4764

    
4765

    
4766
	/* XXX: need to extend to support variable prefix size for v4 */
4767
	$stfiface = "{$interface}_stf";
4768
	if (does_interface_exist($stfiface)) {
4769
		pfSense_interface_destroy($stfiface);
4770
	}
4771
	$tmpstfiface = pfSense_interface_create2("stf");
4772
	pfSense_interface_rename($tmpstfiface, $stfiface);
4773
	pfSense_interface_flags($stfiface, IFF_LINK2);
4774
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4775
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4776
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4777
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4778
	}
4779
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4780
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4781
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4782
	} elseif ($parentmtu > 1300) {
4783
		set_interface_mtu($stfiface, $parentmtu - 20);
4784
	}
4785
	if ($g['debug']) {
4786
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4787
	}
4788

    
4789
	/* write out a default router file */
4790
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4791
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4792

    
4793
	$ip4gateway = get_interface_gateway($interface);
4794
	if (is_ipaddrv4($ip4gateway)) {
4795
		route_add_or_change($wancfg['gateway-6rd'], $ip4gateway);
4796
	}
4797

    
4798
	/* configure dependent interfaces */
4799
	if (!platform_booting()) {
4800
		link_interface_to_track6($interface, "update");
4801
	}
4802

    
4803
	return 0;
4804
}
4805

    
4806
function interface_6to4_configure($interface = "wan", $wancfg) {
4807
	global $config, $g;
4808

    
4809
	/* because this is a tunnel interface we can only function
4810
	 *	with a public IPv4 address on the interface */
4811

    
4812
	if (!is_array($wancfg)) {
4813
		return;
4814
	}
4815

    
4816
	$wanif = get_real_interface($interface);
4817
	$ip4address = find_interface_ip($wanif);
4818
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4819
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4820
		return false;
4821
	}
4822

    
4823
	/* create the long prefix notation for math, save the prefix length */
4824
	$stfprefixlen = 16;
4825
	$stfprefix = Net_IPv6::uncompress("2002::");
4826
	$stfarr = explode(":", $stfprefix);
4827
	$v4prefixlen = "0";
4828

    
4829
	/* we need the hex form of the interface IPv4 address */
4830
	$ip4arr = explode(".", $ip4address);
4831
	$hexwanv4 = "";
4832
	foreach ($ip4arr as $octet) {
4833
		$hexwanv4 .= sprintf("%02x", $octet);
4834
	}
4835

    
4836
	/* we need the hex form of the broker IPv4 address */
4837
	$ip4arr = explode(".", "192.88.99.1");
4838
	$hexbrv4 = "";
4839
	foreach ($ip4arr as $octet) {
4840
		$hexbrv4 .= sprintf("%02x", $octet);
4841
	}
4842

    
4843
	/* binary presentation of the prefix for all 128 bits. */
4844
	$stfprefixbin = "";
4845
	foreach ($stfarr as $element) {
4846
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4847
	}
4848
	/* just save the left prefix length bits */
4849
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4850

    
4851
	/* if the prefix length is not 32 bits we need to shave bits off from the left of the v4 address. */
4852
	$stfbrokerbin = substr(sprintf("%032b", hexdec($hexbrv4)), $v4prefixlen, 32);
4853
	$stfbrokerbin = str_pad($stfprefixstartbin . $stfbrokerbin, 128, "0", STR_PAD_RIGHT);
4854

    
4855
	/* for the local subnet too. */
4856
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4857
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4858

    
4859
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4860
	$stfbrarr = array();
4861
	$stfbrbinarr = array();
4862
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4863
	foreach ($stfbrbinarr as $bin) {
4864
		$stfbrarr[] = dechex(bindec($bin));
4865
	}
4866
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4867

    
4868
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4869
	$stflanarr = array();
4870
	$stflanbinarr = array();
4871
	$stflanbinarr = str_split($stflanbin, 16);
4872
	foreach ($stflanbinarr as $bin) {
4873
		$stflanarr[] = dechex(bindec($bin));
4874
	}
4875
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4876
	$stflanarr[7] = 1;
4877
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4878

    
4879
	/* setup the stf interface */
4880
	if (!is_module_loaded("if_stf")) {
4881
		mwexec("/sbin/kldload if_stf.ko");
4882
	}
4883
	$stfiface = "{$interface}_stf";
4884
	if (does_interface_exist($stfiface)) {
4885
		pfSense_interface_destroy($stfiface);
4886
	}
4887
	$tmpstfiface = pfSense_interface_create2("stf");
4888
	pfSense_interface_rename($tmpstfiface, $stfiface);
4889
	pfSense_interface_flags($stfiface, IFF_LINK2);
4890
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4891

    
4892
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4893
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4894
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4895
	} elseif ($parentmtu > 1300) {
4896
		set_interface_mtu($stfiface, $parentmtu - 20);
4897
	}
4898
	if ($g['debug']) {
4899
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4900
	}
4901

    
4902
	/* write out a default router file */
4903
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4904
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4905

    
4906
	$ip4gateway = get_interface_gateway($interface);
4907
	if (is_ipaddrv4($ip4gateway)) {
4908
		route_add_or_change("192.88.99.1", $ip4gateway);
4909
	}
4910

    
4911
	if (!platform_booting()) {
4912
		link_interface_to_track6($interface, "update");
4913
	}
4914

    
4915
	return 0;
4916
}
4917

    
4918
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4919
	global $config, $g;
4920

    
4921
	if (!is_array($wancfg)) {
4922
		return;
4923
	}
4924

    
4925
	$wanif = get_real_interface($interface, "inet6");
4926
	$dhcp6cconf = "";
4927

    
4928
	if (!empty($config['system']['global-v6duid'])) {
4929
		// Write the DUID file
4930
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4931
		    log_error(gettext("Failed to write user DUID file!"));
4932
		}
4933
	}
4934

    
4935
	/* accept router advertisements for this interface                 */
4936
	/* Moved to early in the function as sometimes interface not ready */
4937
	/* RTSOLD fails as interface does not accept .....                 */
4938

    
4939
	log_error("Accept router advertisements on interface {$wanif} ");
4940
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4941

    
4942
	if ($wancfg['adv_dhcp6_config_file_override']) {
4943
		// DHCP6 Config File Override
4944
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4945
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4946
		// DHCP6 Config File Advanced
4947
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4948
	} else {
4949
		// DHCP6 Config File Basic
4950
		$dhcp6cconf .= "interface {$wanif} {\n";
4951

    
4952
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4953
		if ($wancfg['ipaddrv6'] == "slaac") {
4954
			$dhcp6cconf .= "\tinformation-only;\n";
4955
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4956
			$dhcp6cconf .= "\trequest domain-name;\n";
4957
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4958
			$dhcp6cconf .= "};\n";
4959
		} else {
4960
			$trackiflist = array();
4961
			$iflist = link_interface_to_track6($interface);
4962
			foreach ($iflist as $ifname => $ifcfg) {
4963
				if (is_numeric($ifcfg['track6-prefix-id'])) {
4964
					$trackiflist[$ifname] = $ifcfg;
4965
				}
4966
			}
4967

    
4968
			/* skip address request if this is set */
4969
			if (!isset($wancfg['dhcp6prefixonly'])) {
4970
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
4971
			}
4972
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4973
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
4974
			}
4975

    
4976
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4977
			$dhcp6cconf .= "\trequest domain-name;\n";
4978

    
4979
			/*
4980
			 * dhcp6c will run different scripts depending on
4981
			 * whether dhcpwithoutra is set or unset.
4982
			 */
4983
			if (isset($wancfg['dhcp6withoutra'])) {
4984
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4985
			} else {
4986
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4987
			}
4988
			$dhcp6cconf .= "};\n";
4989

    
4990
			if (!isset($wancfg['dhcp6prefixonly'])) {
4991
				$dhcp6cconf .= "id-assoc na 0 { };\n";
4992
			}
4993

    
4994
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4995
				/* Setup the prefix delegation */
4996
				$dhcp6cconf .= "id-assoc pd 0 {\n";
4997
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4998
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4999
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
5000
				}
5001
				foreach ($trackiflist as $friendly => $ifcfg) {
5002
					if ($g['debug']) {
5003
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
5004
					}
5005
					$realif = get_real_interface($friendly);
5006
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
5007
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
5008
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
5009
					$dhcp6cconf .= "\t};\n";
5010
				}
5011
				unset($preflen, $iflist, $ifcfg, $ifname);
5012
				$dhcp6cconf .= "};\n";
5013
			}
5014
			unset($trackiflist);
5015
		}
5016
	}
5017

    
5018
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
5019
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
5020

    
5021
	/* wide-dhcp6c works for now. */
5022
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
5023
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
5024
		unset($dhcp6cconf);
5025
		return 1;
5026
	}
5027
	unset($dhcp6cconf);
5028

    
5029
	/*************** Script Debug Logging ***************************
5030
	Both dhcp6 scripts now have a logging message built in.
5031
	These logging messages ONLY appear if dhcp6c debug logging is set.
5032
	The logging messages appear in the dhcp section of the logs,
5033
	not in system.
5034

    
5035
	These scripts now also take advantage of the REASON= env vars
5036
	supplied by dhcp6c.
5037
	****************************************************************/
5038

    
5039
	/* Script create for dhcp6withoutRA mode */
5040
	/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
5041
	$dhcp6cscriptwithoutra = "#!/bin/sh\n";
5042
	$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
5043
	$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
5044
	$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
5045
	$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
5046
	// Need to pass params to  the final script
5047
	$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
5048
	$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
5049
	$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
5050
	$dhcp6cscriptwithoutra .= "case \$REASON in\n";
5051
	$dhcp6cscriptwithoutra .= "REQUEST)\n";
5052
	$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
5053
	$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -M {$g['varetc_path']}/rtsold_{$wanif}_script.sh -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
5054
	if ($debugOption == '-D') {
5055
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rtsold\"\n";
5056
	}
5057
	$dhcp6cscriptwithoutra .= ";;\n";
5058
	$dhcp6cscriptwithoutra .= "REBIND)\n";
5059
	if ($debugOption == '-D') {
5060
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
5061
	}
5062
	$dhcp6cscriptwithoutra .= ";;\n";
5063
	if (isset($wancfg['dhcp6norelease'])) {
5064
		$dhcp6cscriptwithoutra .= "EXIT)\n";
5065
	} else {
5066
		$dhcp6cscriptwithoutra .= "RELEASE)\n";
5067
	}
5068
	if ($debugOption == '-D') {
5069
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
5070
	}
5071
	$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5072
	$dhcp6cscriptwithoutra .= ";;\n";
5073
	$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
5074
	if ($debugOption == '-D') {
5075
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5076
	}
5077
	$dhcp6cscriptwithoutra .= "esac\n";
5078
	if (!@file_put_contents(
5079
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
5080
	    $dhcp6cscriptwithoutra)) {
5081
		printf("Error: cannot open " .
5082
		    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
5083
		    "interface_dhcpv6_configure() for writing.\n");
5084
		unset($dhcp6cscriptwithoutra);
5085
		return 1;
5086
	}
5087

    
5088
	unset($dhcp6cscriptwithoutra);
5089
	@chmod(
5090
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
5091
	    0755);
5092

    
5093
	/*
5094
	 * Dual mode wan_dhcp6c script with variations depending on node
5095
	 * dhcp6 will run the wan ipv6 configure
5096
	 */
5097
	$dhcp6cscript  = "#!/bin/sh\n";
5098
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
5099
	if (!isset($wancfg['dhcp6withoutra'])) {
5100
		$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
5101
		$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
5102
		$dhcp6cscript .= "case \$REASON in\n";
5103
		$dhcp6cscript .= "REBIND)\n";
5104
		if ($debugOption == '-D') {
5105
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
5106
		}
5107
		$dhcp6cscript .= ";;\n";
5108
		$dhcp6cscript .= "REQUEST|";
5109
		if (isset($wancfg['dhcp6norelease'])) {
5110
			$dhcp6cscript .= "EXIT)\n";
5111
		} else {
5112
			$dhcp6cscript .= "RELEASE)\n";
5113
		}
5114
		if ($debugOption == '-D') {
5115
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c RELEASE, REQUEST or EXIT on {$wanif} running rc.newwanipv6\"\n";
5116
		}
5117
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5118
		$dhcp6cscript .= ";;\n";
5119
		$dhcp6cscript .= "RENEW|INFO)\n";
5120
		if ($debugOption == '-D') {
5121
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5122
		}
5123
		$dhcp6cscript .= "esac\n";
5124
	} else {
5125
		// Need to get the parameters from the dhcp6cwithoutRA run
5126
		$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
5127
		$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
5128
		$dhcp6cscript .= "/bin/sleep 1\n";
5129
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5130
	}
5131

    
5132
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5133
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
5134
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
5135
		unset($dhcp6cscript);
5136
		return 1;
5137
	}
5138
	unset($dhcp6cscript);
5139
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
5140

    
5141
	$rtsoldscript = <<<EOD
5142
#!/bin/sh
5143
# This shell script launches dhcp6c and configured gateways for this interface.
5144
if [ -n "\$2" ]; then
5145
	echo \$2 > {$g['tmp_path']}/{$wanif}_routerv6
5146
	echo \$2 > {$g['tmp_path']}/{$wanif}_defaultgwv6
5147
	/usr/bin/logger -t rtsold "Received RA specifying route \$2 for interface {$interface}({$wanif})"
5148
fi
5149

    
5150
EOD;
5151

    
5152
	/* non ipoe Process */
5153
	if (!isset($wancfg['dhcp6withoutra'])) {
5154
		/*
5155
		 * We only want this script to run once, and if it runs twice
5156
		 * then do not launch dhcp6c again, this only happens if
5157
		 * dhcpwithoutra is not set.
5158
		 *
5159
		 * Check for a lock file, trying to prevent multiple instances
5160
		 * of dhcp6c being launched
5161
		 */
5162
		$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n";
5163
		/*
5164
		 * Create the lock file, trying to prevent multiple instances
5165
		 * of dhcp6c being launched
5166
		 */
5167
		$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n";
5168
		$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
5169
		$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
5170
		$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
5171
		$rtsoldscript .= "\t\t/bin/sleep 1\n";
5172
		$rtsoldscript .= "\tfi\n";
5173
		$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
5174
		    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf " .
5175
		    "-p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
5176
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
5177
		$rtsoldscript .= "else\n";
5178
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
5179
		$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c_{$wanif}.pid\")\n";
5180
		$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
5181
		$rtsoldscript .= "fi\n";
5182
	} else {
5183
		/*
5184
		 * The script needs to run in dhcp6withoutra mode as RA may
5185
		 * not have been received, or there can be a delay with
5186
		 * certain ISPs
5187
		 */
5188
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
5189
		$rtsoldscript .= "/bin/sleep 1\n";
5190
	}
5191
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5192
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
5193
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
5194
		unset($rtsoldscript);
5195
		return 1;
5196
	}
5197
	unset($rtsoldscript);
5198
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
5199

    
5200
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
5201
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
5202
		log_error("Killing running rtsold process");
5203
		sleep(2);
5204
	}
5205

    
5206
	if (isset($wancfg['dhcp6withoutra'])) {
5207
		/*
5208
		 * Start dhcp6c here if we don't want to wait for ra - calls
5209
		 * separate function
5210
		 *
5211
		 * In this mode dhcp6c launches rtsold via its script. RTSOLD
5212
		 * will then run the configure on receipt of the RA.
5213
		 *
5214
		 * Already started. interface_dhcpv6_configure() appears to get
5215
		 * called multiple times.
5216
		 *
5217
		 * Taking the interface down or releasing will kill the client.
5218
		 */
5219
		if (!file_exists("/tmp/dhcp6c_{$wanif}_lock"))
5220
		{
5221
			/*
5222
			 * If the interface is being brought up, wait for the
5223
			 * interface to configure accept RA before launching.
5224
			 * Otherwise it is not ready to accept and will fail.
5225
			 */
5226
			sleep(3);
5227
			run_dhcp6client_process($wanif,$interface,$wancfg);
5228
		}
5229
	} else {
5230
		/*
5231
		 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
5232
		 * ( it does not background, it exits! ) It will launch dhcp6c
5233
		 * if dhcpwihtoutra is not set
5234
		 */
5235
		log_error("Starting rtsold process");
5236
		sleep(2);
5237
		mwexec("/usr/sbin/rtsold -1 " .
5238
		    "-p {$g['varrun_path']}/rtsold_{$wanif}.pid " .
5239
		    "-M {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
5240
		    "-O {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
5241
		    $wanif);
5242
	}
5243
	/*
5244
	 * NOTE: will be called from rtsold invoked script
5245
	 * link_interface_to_track6($interface, "update");
5246
	 */
5247

    
5248
	return 0;
5249
}
5250

    
5251
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5252
	global $g;
5253

    
5254
	$send_options = "";
5255
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
5256
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
5257
		foreach ($options as $option) {
5258
			$send_options .= "\tsend " . trim($option) . ";\n";
5259
		}
5260
	}
5261

    
5262
	$request_options = "";
5263
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5264
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5265
		foreach ($options as $option) {
5266
			$request_options .= "\trequest " . trim($option) . ";\n";
5267
		}
5268
	}
5269

    
5270
	$information_only = "";
5271
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5272
		$information_only = "\tinformation-only;\n";
5273
	}
5274

    
5275
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5276
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5277
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5278
	}
5279

    
5280
	$interface_statement  = "interface";
5281
	$interface_statement .= " {$wanif}";
5282
	$interface_statement .= " {\n";
5283
	$interface_statement .= "$send_options";
5284
	$interface_statement .= "$request_options";
5285
	$interface_statement .= "$information_only";
5286
	$interface_statement .= "$script";
5287
	$interface_statement .= "};\n";
5288

    
5289
	$id_assoc_statement_address = "";
5290
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5291
		$id_assoc_statement_address .= "id-assoc";
5292
		$id_assoc_statement_address .= " na";
5293
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5294
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5295
		}
5296
		$id_assoc_statement_address .= " { ";
5297

    
5298
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5299
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5300
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5301
			$id_assoc_statement_address .= "\n\taddress";
5302
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5303
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5304
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5305
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5306
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5307
			}
5308
			$id_assoc_statement_address .= ";\n";
5309
		}
5310

    
5311
		$id_assoc_statement_address .= "};\n";
5312
	}
5313

    
5314
	$id_assoc_statement_prefix = "";
5315
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5316
		$id_assoc_statement_prefix .= "id-assoc";
5317
		$id_assoc_statement_prefix .= " pd";
5318
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5319
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5320
		}
5321
		$id_assoc_statement_prefix .= " { ";
5322

    
5323
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5324
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5325
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5326
			$id_assoc_statement_prefix .= "\n\tprefix";
5327
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5328
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5329
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5330
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5331
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5332
			}
5333
			$id_assoc_statement_prefix .= ";";
5334
		}
5335

    
5336
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
5337
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
5338
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
5339
			$id_assoc_statement_prefix .= " {$realif}";
5340
			$id_assoc_statement_prefix .= " {\n";
5341
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
5342
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
5343
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
5344
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
5345
			}
5346
			$id_assoc_statement_prefix .= "\t};";
5347
		}
5348

    
5349
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5350
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5351
			$id_assoc_statement_prefix .= "\n";
5352
		}
5353

    
5354
		$id_assoc_statement_prefix .= "};\n";
5355
	}
5356

    
5357
	$authentication_statement = "";
5358
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
5359
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
5360
		$authentication_statement .= "authentication";
5361
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
5362
		$authentication_statement .= " {\n";
5363
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
5364
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
5365
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
5366
		}
5367
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
5368
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
5369
		}
5370
		$authentication_statement .= "};\n";
5371
	}
5372

    
5373
	$key_info_statement = "";
5374
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5375
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5376
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5377
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5378
		$key_info_statement .= "keyinfo";
5379
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5380
		$key_info_statement .= " {\n";
5381
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5382
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5383
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5384
		if (preg_match("/((([0-9]{4}-)?[0-9]{2}[0-9]{2} )?[0-9]{2}:[0-9]{2})||(foreever)/", $wancfg['adv_dhcp6_key_info_statement_expire'])) {
5385
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5386
		}
5387
		$key_info_statement .= "};\n";
5388
	}
5389

    
5390
	$dhcp6cconf  = $interface_statement;
5391
	$dhcp6cconf .= $id_assoc_statement_address;
5392
	$dhcp6cconf .= $id_assoc_statement_prefix;
5393
	$dhcp6cconf .= $authentication_statement;
5394
	$dhcp6cconf .= $key_info_statement;
5395

    
5396
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5397

    
5398
	return $dhcp6cconf;
5399
}
5400

    
5401

    
5402
function DHCP6_Config_File_Override($wancfg, $wanif) {
5403

    
5404
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5405

    
5406
	if ($dhcp6cconf === false) {
5407
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5408
		return '';
5409
	} else {
5410
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5411
	}
5412
}
5413

    
5414

    
5415
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5416

    
5417
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5418

    
5419
	return $dhcp6cconf;
5420
}
5421

    
5422

    
5423
function interface_dhcp_configure($interface = "wan") {
5424
	global $config, $g, $vlanprio_values;
5425

    
5426
	$ifcfg = $config['interfaces'][$interface];
5427
	if (empty($ifcfg)) {
5428
		$ifcfg = array();
5429
	}
5430

    
5431
	$dhclientconf_vlantag = "";
5432
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5433
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5434
	}
5435

    
5436
	/* generate dhclient_wan.conf */
5437
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5438
	if (!$fd) {
5439
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5440
		return 1;
5441
	}
5442

    
5443
	if ($ifcfg['dhcphostname']) {
5444
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5445
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5446
	} else {
5447
		$dhclientconf_hostname = "";
5448
	}
5449

    
5450
	$realif = get_real_interface($interface);
5451
	if (empty($realif)) {
5452
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5453
		return 0;
5454
	}
5455
	$dhclientconf = "";
5456

    
5457
	$dhclientconf .= <<<EOD
5458
interface "{$realif}" {
5459
	supersede interface-mtu 0;
5460
	timeout 60;
5461
	retry 15;
5462
	select-timeout 0;
5463
	initial-interval 1;
5464
	{$dhclientconf_vlantag}
5465
	{$dhclientconf_hostname}
5466
	script "/usr/local/sbin/pfSense-dhclient-script";
5467
EOD;
5468

    
5469
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5470
		$dhclientconf .= <<<EOD
5471

    
5472
	reject {$ifcfg['dhcprejectfrom']};
5473
EOD;
5474
	}
5475
	$dhclientconf .= <<<EOD
5476

    
5477
}
5478

    
5479
EOD;
5480

    
5481
	// DHCP Config File Advanced
5482
	if ($ifcfg['adv_dhcp_config_advanced']) {
5483
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5484
	}
5485

    
5486
	if (is_ipaddr($ifcfg['alias-address'])) {
5487
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5488
		$dhclientconf .= <<<EOD
5489
alias {
5490
	interface "{$realif}";
5491
	fixed-address {$ifcfg['alias-address']};
5492
	option subnet-mask {$subnetmask};
5493
}
5494

    
5495
EOD;
5496
	}
5497

    
5498
	// DHCP Config File Override
5499
	if ($ifcfg['adv_dhcp_config_file_override']) {
5500
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5501
	}
5502

    
5503
	fwrite($fd, $dhclientconf);
5504
	fclose($fd);
5505

    
5506
	/* bring wan interface up before starting dhclient */
5507
	if ($realif) {
5508
		interfaces_bring_up($realif);
5509
	}
5510

    
5511
	/* Make sure dhclient is not running */
5512
	kill_dhclient_process($realif);
5513

    
5514
	/* fire up dhclient */
5515
	mwexec("/sbin/dhclient -c {$g['varetc_path']}/dhclient_{$interface}.conf {$realif} > {$g['tmp_path']}/{$realif}_output 2> {$g['tmp_path']}/{$realif}_error_output");
5516

    
5517
	return 0;
5518
}
5519

    
5520
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5521

    
5522
	$hostname = "";
5523
	if ($ifcfg['dhcphostname'] != '') {
5524
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5525
	}
5526

    
5527
	/* DHCP Protocol Timings */
5528
	$protocol_timings = array ('adv_dhcp_pt_timeout' => "timeout", 'adv_dhcp_pt_retry' => "retry", 'adv_dhcp_pt_select_timeout' => "select-timeout", 'adv_dhcp_pt_reboot' => "reboot", 'adv_dhcp_pt_backoff_cutoff' => "backoff-cutoff", 'adv_dhcp_pt_initial_interval' => "initial-interval");
5529
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5530
		$pt_variable = "{$Protocol_Timing}";
5531
		${$pt_variable} = "";
5532
		if ($ifcfg[$Protocol_Timing] != "") {
5533
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5534
		}
5535
	}
5536

    
5537
	$send_options = "";
5538
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5539
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5540
		foreach ($options as $option) {
5541
			$send_options .= "\tsend " . trim($option) . ";\n";
5542
		}
5543
	}
5544

    
5545
	$request_options = "";
5546
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5547
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5548
	}
5549

    
5550
	$required_options = "";
5551
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5552
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5553
	}
5554

    
5555
	$option_modifiers = "";
5556
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5557
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5558
		foreach ($modifiers as $modifier) {
5559
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5560
		}
5561
	}
5562

    
5563
	$dhclientconf  = "interface \"{$realif}\" {\n";
5564
	$dhclientconf .= "\n";
5565
	$dhclientconf .= "\tsupersede interface-mtu 0;\n";
5566
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5567
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5568
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5569
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5570
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5571
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5572
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5573
	$dhclientconf .= "\n";
5574
	$dhclientconf .= "# DHCP Protocol Options\n";
5575
	$dhclientconf .= "{$hostname}";
5576
	$dhclientconf .= "{$send_options}";
5577
	$dhclientconf .= "{$request_options}";
5578
	$dhclientconf .= "{$required_options}";
5579
	$dhclientconf .= "{$option_modifiers}";
5580
	$dhclientconf .= "\n";
5581
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5582
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5583
	}
5584
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5585
	$dhclientconf .= "}\n";
5586

    
5587
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5588

    
5589
	return $dhclientconf;
5590
}
5591

    
5592
function DHCP_Config_Option_Split($option_string) {
5593
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5594
	return $matches ? $matches[0] : [];
5595
}
5596

    
5597
function DHCP_Config_File_Override($ifcfg, $realif) {
5598

    
5599
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5600

    
5601
	if ($dhclientconf === false) {
5602
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5603
		return '';
5604
	} else {
5605
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5606
	}
5607
}
5608

    
5609

    
5610
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5611

    
5612
	/* Apply Interface Substitutions */
5613
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5614

    
5615
	/* Apply Hostname Substitutions */
5616
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5617

    
5618
	/* Arrays of MAC Address Types, Cases, Delimiters */
5619
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5620
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5621
	$various_mac_cases      = array("U", "L");
5622
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5623

    
5624
	/* Apply MAC Address Substitutions */
5625
	foreach ($various_mac_types as $various_mac_type) {
5626
		foreach ($various_mac_cases as $various_mac_case) {
5627
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5628

    
5629
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5630
				if ($res !== false) {
5631

    
5632
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5633
					if ("$various_mac_case" == "U") {
5634
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5635
					}
5636
					if ("$various_mac_case" == "L") {
5637
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5638
					}
5639

    
5640
					if ("$various_mac_type" == "mac_addr_hex") {
5641
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5642
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5643
						$dhcpclientconf_mac_hex = "";
5644
						$delimiter = "";
5645
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5646
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5647
							$delimiter = ":";
5648
						}
5649
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5650
					}
5651

    
5652
					/* MAC Address Delimiter Substitutions */
5653
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5654

    
5655
					/* Apply MAC Address Substitutions */
5656
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5657
				}
5658
			}
5659
		}
5660
	}
5661

    
5662
	return $dhclientconf;
5663
}
5664

    
5665
function interfaces_group_setup() {
5666
	global $config;
5667

    
5668
	if (!isset($config['ifgroups']['ifgroupentry']) ||
5669
	    !is_array($config['ifgroups']['ifgroupentry'])) {
5670
		return;
5671
	}
5672

    
5673
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5674
		interface_group_setup($groupar);
5675
	}
5676

    
5677
	return;
5678
}
5679

    
5680
function interface_group_setup(&$groupname /* The parameter is an array */) {
5681
	global $config;
5682

    
5683
	if (!is_array($groupname)) {
5684
		return;
5685
	}
5686
	$members = explode(" ", $groupname['members']);
5687
	foreach ($members as $ifs) {
5688
		$realif = get_real_interface($ifs);
5689
		if ($realif && does_interface_exist($realif)) {
5690
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5691
		}
5692
	}
5693

    
5694
	return;
5695
}
5696

    
5697
function is_interface_group($if) {
5698
	global $config;
5699

    
5700
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5701
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5702
			if ($groupentry['ifname'] === $if) {
5703
				return true;
5704
			}
5705
		}
5706
	}
5707

    
5708
	return false;
5709
}
5710

    
5711
function interface_group_add_member($interface, $groupname) {
5712
	$interface = get_real_interface($interface);
5713
	if (does_interface_exist($interface)) {
5714
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5715
	}
5716
}
5717

    
5718
/* COMPAT Function */
5719
function convert_friendly_interface_to_real_interface_name($interface) {
5720
	return get_real_interface($interface);
5721
}
5722

    
5723
/* COMPAT Function */
5724
function get_real_wan_interface($interface = "wan") {
5725
	return get_real_interface($interface);
5726
}
5727

    
5728
/* COMPAT Function */
5729
function get_current_wan_address($interface = "wan") {
5730
	return get_interface_ip($interface);
5731
}
5732

    
5733
/*
5734
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5735
 */
5736
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5737
	global $config;
5738

    
5739
	/* XXX: For speed reasons reference directly the interface array */
5740
	init_config_arr(array('interfaces'));
5741
	$ifdescrs = &$config['interfaces'];
5742
	//$ifdescrs = get_configured_interface_list(true);
5743

    
5744
	foreach ($ifdescrs as $if => $ifname) {
5745
		if ($if == $interface || $ifname['if'] == $interface) {
5746
			return $if;
5747
		}
5748

    
5749
		if (get_real_interface($if) == $interface) {
5750
			return $if;
5751
		}
5752

    
5753
		if ($checkparent == false) {
5754
			continue;
5755
		}
5756

    
5757
		$int = get_parent_interface($if, true);
5758
		if (is_array($int)) {
5759
			foreach ($int as $iface) {
5760
				if ($iface == $interface) {
5761
					return $if;
5762
				}
5763
			}
5764
		}
5765
	}
5766

    
5767
	if ($interface == "enc0") {
5768
		return 'IPsec';
5769
	}
5770
}
5771

    
5772
/* attempt to resolve interface to friendly descr */
5773
function convert_friendly_interface_to_friendly_descr($interface) {
5774
	global $config;
5775

    
5776
	switch ($interface) {
5777
		case "l2tp":
5778
			$ifdesc = "L2TP";
5779
			break;
5780
		case "pptp":
5781
			$ifdesc = "PPTP";
5782
			break;
5783
		case "pppoe":
5784
			$ifdesc = "PPPoE";
5785
			break;
5786
		case "openvpn":
5787
			$ifdesc = "OpenVPN";
5788
			break;
5789
		case "lo0":
5790
			$ifdesc = "Loopback";
5791
			break;
5792
		case "enc0":
5793
		case "ipsec":
5794
		case "IPsec":
5795
			$ifdesc = "IPsec";
5796
			break;
5797
		default:
5798
			if (isset($config['interfaces'][$interface])) {
5799
				if (empty($config['interfaces'][$interface]['descr'])) {
5800
					$ifdesc = strtoupper($interface);
5801
				} else {
5802
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5803
				}
5804
				break;
5805
			} elseif (substr($interface, 0, 4) == '_vip') {
5806
				if (is_array($config['virtualip']['vip'])) {
5807
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5808
						if ($vip['mode'] == "carp") {
5809
							if ($interface == "_vip{$vip['uniqid']}") {
5810
								$descr = $vip['subnet'];
5811
								$descr .= " (vhid {$vip['vhid']})";
5812
								if (!empty($vip['descr'])) {
5813
									$descr .= " - " .$vip['descr'];
5814
								}
5815
								return $descr;
5816
							}
5817
						}
5818
					}
5819
				}
5820
			} elseif (substr($interface, 0, 5) == '_lloc') {
5821
				return get_interface_linklocal($interface);
5822
			} else {
5823
				if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5824
					foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
5825
						if ($ifgen['ifname'] === $interface) {
5826
							return $ifgen['ifname'];
5827
						}
5828
					}
5829
				}
5830

    
5831
				/* if list */
5832
				$ifdescrs = get_configured_interface_with_descr(true);
5833
				foreach ($ifdescrs as $if => $ifname) {
5834
					if ($if == $interface || $ifname == $interface) {
5835
						return $ifname;
5836
					}
5837
				}
5838
			}
5839
			break;
5840
	}
5841

    
5842
	return $ifdesc;
5843
}
5844

    
5845
function convert_real_interface_to_friendly_descr($interface) {
5846

    
5847
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5848

    
5849
	if (!empty($ifdesc)) {
5850
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5851
	}
5852

    
5853
	return $interface;
5854
}
5855

    
5856
/*
5857
 *  get_parent_interface($interface):
5858
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5859
 *				or virtual interface (i.e. vlan)
5860
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5861
 *			-- returns $interface passed in if $interface parent is not found
5862
 *			-- returns empty array if an invalid interface is passed
5863
 *	(Only handles ppps and vlans now.)
5864
 */
5865
function get_parent_interface($interface, $avoidrecurse = false) {
5866
	global $config;
5867

    
5868
	$parents = array();
5869
	//Check that we got a valid interface passed
5870
	$realif = get_real_interface($interface);
5871
	if ($realif == NULL) {
5872
		return $parents;
5873
	}
5874

    
5875
	// If we got a real interface, find it's friendly assigned name
5876
	if ($interface == $realif && $avoidrecurse == false) {
5877
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5878
	}
5879

    
5880
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5881
		$ifcfg = $config['interfaces'][$interface];
5882
		switch ($ifcfg['ipaddr']) {
5883
			case "ppp":
5884
			case "pppoe":
5885
			case "pptp":
5886
			case "l2tp":
5887
				if (empty($parents)) {
5888
					if (is_array($config['ppps']['ppp'])) {
5889
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5890
							if ($ifcfg['if'] == $ppp['if']) {
5891
								$ports = explode(',', $ppp['ports']);
5892
								foreach ($ports as $pid => $parent_if) {
5893
									$parents[$pid] = get_real_interface($parent_if);
5894
								}
5895
								break;
5896
							}
5897
						}
5898
					}
5899
				}
5900
				break;
5901
			case "dhcp":
5902
			case "static":
5903
			default:
5904
				// Handle _vlans
5905
				$vlan = interface_is_vlan($ifcfg['if']);
5906
				if ($vlan != NULL) {
5907
					$parents[0] = $vlan['if'];
5908
				}
5909
				break;
5910
		}
5911
	}
5912

    
5913
	if (empty($parents)) {
5914
		// Handle _vlans not assigned to an interface
5915
		$vlan = interface_is_vlan($realif);
5916
		if ($vlan != NULL) {
5917
			$parents[0] = $vlan['if'];
5918
		}
5919
	}
5920

    
5921
	if (empty($parents)) {
5922
		/* Handle LAGGs. */
5923
		$lagg = interface_is_type($realif, 'lagg');
5924
		if ($lagg != NULL && isset($lagg['members'])) {
5925
			$parents = explode(",", $lagg['members']);
5926
		}
5927
	}
5928

    
5929
	if (empty($parents)) {
5930
		$parents[0] = $realif;
5931
	}
5932

    
5933
	return $parents;
5934
}
5935

    
5936
/*
5937
 *  get_parent_physical_interface($interface):
5938
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5939
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5940
 */
5941
function get_parent_physical_interface($interface) {
5942
	global $config;
5943

    
5944
	$realif = get_parent_interface($interface);
5945

    
5946
	if (substr($realif[0], 0, 4) == "lagg") {
5947
		foreach ($config['laggs']['lagg'] as $lagg) {
5948
			if ($realif[0] == $lagg['laggif']) {
5949
				return explode(",", $lagg['members']);
5950
			}
5951
		}
5952
	} else {
5953
		return $realif;
5954
	}
5955
}
5956

    
5957
function interface_is_wireless_clone($wlif) {
5958
	if (!stristr($wlif, "_wlan")) {
5959
		return false;
5960
	} else {
5961
		return true;
5962
	}
5963
}
5964

    
5965
function interface_get_wireless_base($wlif) {
5966
	if (!stristr($wlif, "_wlan")) {
5967
		return $wlif;
5968
	} else {
5969
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5970
	}
5971
}
5972

    
5973
function interface_get_wireless_clone($wlif) {
5974
	if (!stristr($wlif, "_wlan")) {
5975
		return $wlif . "_wlan0";
5976
	} else {
5977
		return $wlif;
5978
	}
5979
}
5980

    
5981
function interface_list_wireless() {
5982
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5983

    
5984
	$result = array();
5985
	foreach ($portlist as $port) {
5986
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5987
			continue;
5988
		}
5989

    
5990
		$desc = $port . " ( " . get_single_sysctl(
5991
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5992

    
5993
		$result[] = array(
5994
		    "if" => $port,
5995
		    "descr" => $desc
5996
		);
5997
	}
5998

    
5999
	return $result;
6000
}
6001

    
6002
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = false) {
6003
	global $config, $g;
6004

    
6005
	$wanif = NULL;
6006

    
6007
	switch ($interface) {
6008
		case "l2tp":
6009
			$wanif = "l2tp";
6010
			break;
6011
		case "pptp":
6012
			$wanif = "pptp";
6013
			break;
6014
		case "pppoe":
6015
			$wanif = "pppoe";
6016
			break;
6017
		case "openvpn":
6018
			$wanif = "openvpn";
6019
			break;
6020
		case "IPsec":
6021
		case "ipsec":
6022
		case "enc0":
6023
			$wanif = "enc0";
6024
			break;
6025
		case "ppp":
6026
			$wanif = "ppp";
6027
			break;
6028
		default:
6029
			if (substr($interface, 0, 4) == '_vip') {
6030
				$wanif = get_configured_vip_interface($interface);
6031
				if (!empty($wanif)) {
6032
					$wanif = get_real_interface($wanif);
6033
				}
6034
				break;
6035
			} elseif (substr($interface, 0, 5) == '_lloc') {
6036
				$interface = substr($interface, 5);
6037
			} elseif (interface_is_vlan($interface) != NULL ||
6038
			    does_interface_exist($interface, $flush)) {
6039
				/*
6040
				 * If a real interface was already passed simply
6041
				 * pass the real interface back.  This encourages
6042
				 * the usage of this function in more cases so that
6043
				 * we can combine logic for more flexibility.
6044
				 */
6045
				$wanif = $interface;
6046
				break;
6047
			}
6048

    
6049
			if (empty($config['interfaces'][$interface])) {
6050
				break;
6051
			}
6052

    
6053
			$cfg = &$config['interfaces'][$interface];
6054

    
6055
			if ($family == "inet6") {
6056
				switch ($cfg['ipaddrv6']) {
6057
					case "6rd":
6058
					case "6to4":
6059
						$wanif = "{$interface}_stf";
6060
						break;
6061
					case 'pppoe':
6062
					case 'ppp':
6063
					case 'l2tp':
6064
					case 'pptp':
6065
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6066
							$wanif = interface_get_wireless_clone($cfg['if']);
6067
						} else {
6068
							$wanif = $cfg['if'];
6069
						}
6070
						break;
6071
					default:
6072
						switch ($cfg['ipaddr']) {
6073
							case 'pppoe':
6074
							case 'ppp':
6075
							case 'l2tp':
6076
							case 'pptp':
6077
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
6078
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) ||
6079
								    isset($cfg['ipv6usev4iface']) || isset($cfg['slaacusev4iface'])) {
6080
									$wanif = $cfg['if'];
6081
								} else {
6082
									$parents = get_parent_interface($interface);
6083
									if (!empty($parents[0])) {
6084
										$wanif = $parents[0];
6085
									} else {
6086
										$wanif = $cfg['if'];
6087
									}
6088
								}
6089
								break;
6090
							default:
6091
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6092
									$wanif = interface_get_wireless_clone($cfg['if']);
6093
								} else {
6094
									$wanif = $cfg['if'];
6095
								}
6096
								break;
6097
						}
6098
						break;
6099
				}
6100
			} else {
6101
				// Wireless cloned NIC support (FreeBSD 8+)
6102
				// interface name format: $parentnic_wlanparentnic#
6103
				// example: ath0_wlan0
6104
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6105
					$wanif = interface_get_wireless_clone($cfg['if']);
6106
				} else {
6107
					$wanif = $cfg['if'];
6108
				}
6109
			}
6110
			break;
6111
	}
6112

    
6113
	return $wanif;
6114
}
6115

    
6116
/* Guess the physical interface by providing a IP address */
6117
function guess_interface_from_ip($ipaddress) {
6118

    
6119
	if (!is_ipaddr($ipaddress)) {
6120
		return false;
6121
	}
6122

    
6123
	$route = route_get($ipaddress, '', true);
6124
	if (empty($route)) {
6125
		return false;
6126
	}
6127

    
6128
	if (!empty($route[0]['interface-name'])) {
6129
		return $route[0]['interface-name'];
6130
	}
6131

    
6132
	return false;
6133
}
6134

    
6135
/*
6136
 * find_ip_interface($ip): return the interface where an ip is defined
6137
 *   (or if $bits is specified, where an IP within the subnet is defined)
6138
 */
6139
function find_ip_interface($ip, $bits = null) {
6140
	if (!is_ipaddr($ip)) {
6141
		return false;
6142
	}
6143

    
6144
	$isv6ip = is_ipaddrv6($ip);
6145

    
6146
	/* if list */
6147
	$ifdescrs = get_configured_interface_list();
6148

    
6149
	foreach ($ifdescrs as $ifdescr => $ifname) {
6150
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
6151
		if (is_null($ifip)) {
6152
			continue;
6153
		}
6154
		if (is_null($bits)) {
6155
			if ($ip == $ifip) {
6156
				$int = get_real_interface($ifname);
6157
				return $int;
6158
			}
6159
		} else {
6160
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
6161
				$int = get_real_interface($ifname);
6162
				return $int;
6163
			}
6164
		}
6165
	}
6166

    
6167
	return false;
6168
}
6169

    
6170
/*
6171
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
6172
 *   (or if $bits is specified, where an IP within the subnet is found)
6173
 */
6174
function find_virtual_ip_alias($ip, $bits = null) {
6175
	global $config;
6176

    
6177
	if (!is_array($config['virtualip']['vip'])) {
6178
		return false;
6179
	}
6180
	if (!is_ipaddr($ip)) {
6181
		return false;
6182
	}
6183

    
6184
	$isv6ip = is_ipaddrv6($ip);
6185

    
6186
	foreach ($config['virtualip']['vip'] as $vip) {
6187
		if ($vip['mode'] === "ipalias") {
6188
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
6189
				continue;
6190
			}
6191
			if (is_null($bits)) {
6192
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
6193
					return $vip;
6194
				}
6195
			} else {
6196
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
6197
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
6198
					return $vip;
6199
				}
6200
			}
6201
		}
6202
	}
6203
	return false;
6204
}
6205

    
6206
function link_interface_to_track6($int, $action = "") {
6207
	global $config;
6208

    
6209
	if (empty($int)) {
6210
		return;
6211
	}
6212

    
6213
	if (is_array($config['interfaces'])) {
6214
		$list = array();
6215
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
6216
			if (!isset($ifcfg['enable'])) {
6217
				continue;
6218
			}
6219
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
6220
				if ($action == "update") {
6221
					interface_track6_configure($ifname, $ifcfg);
6222
				} elseif ($action == "") {
6223
					$list[$ifname] = $ifcfg;
6224
				}
6225
			}
6226
		}
6227
		return $list;
6228
	}
6229
}
6230

    
6231
function interface_find_child_cfgmtu($realiface) {
6232
	global $config;
6233

    
6234
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
6235
	$vlans = link_interface_to_vlans($realiface);
6236
	$qinqs = link_interface_to_qinqs($realiface);
6237
	$bridge = link_interface_to_bridge($realiface);
6238
	if (!empty($interface)) {
6239
		$gifs = link_interface_to_tunnelif($interface, 'gif');
6240
		$gres = link_interface_to_tunnelif($interface, 'gre');
6241
	} else {
6242
		$gifs = array();
6243
		$gres = array();
6244
	}
6245

    
6246
	$mtu = 0;
6247
	if (is_array($vlans)) {
6248
		foreach ($vlans as $vlan) {
6249
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
6250
			if (empty($ifass)) {
6251
				continue;
6252
			}
6253
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6254
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6255
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6256
				}
6257
			}
6258
		}
6259
	}
6260
	if (is_array($qinqs)) {
6261
		foreach ($qinqs as $qinq) {
6262
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
6263
			if (empty($ifass)) {
6264
				continue;
6265
			}
6266
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6267
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6268
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6269
				}
6270
			}
6271
		}
6272
	}
6273
	if (is_array($gifs)) {
6274
		foreach ($gifs as $gif) {
6275
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
6276
			if (empty($ifass)) {
6277
				continue;
6278
			}
6279
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6280
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6281
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6282
				}
6283
			}
6284
		}
6285
	}
6286
	if (is_array($gres)) {
6287
		foreach ($gres as $gre) {
6288
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
6289
			if (empty($ifass)) {
6290
				continue;
6291
			}
6292
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6293
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6294
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6295
				}
6296
			}
6297
		}
6298
	}
6299
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
6300
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
6301
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6302
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
6303
		}
6304
	}
6305
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
6306

    
6307
	return $mtu;
6308
}
6309

    
6310
function link_interface_to_vlans($int, $action = "") {
6311
	global $config;
6312

    
6313
	if (empty($int)) {
6314
		return;
6315
	}
6316

    
6317
	if (is_array($config['vlans']['vlan'])) {
6318
		$ifaces = array();
6319
		foreach ($config['vlans']['vlan'] as $vlan) {
6320
			if ($int == $vlan['if']) {
6321
				if ($action == "update") {
6322
					interfaces_bring_up($int);
6323
				} else {
6324
					$ifaces[$vlan['tag']] = $vlan;
6325
				}
6326
			}
6327
		}
6328
		if (!empty($ifaces)) {
6329
			return $ifaces;
6330
		}
6331
	}
6332
}
6333

    
6334
function link_interface_to_qinqs($int, $action = "") {
6335
	global $config;
6336

    
6337
	if (empty($int)) {
6338
		return;
6339
	}
6340

    
6341
	if (is_array($config['qinqs']['qinqentry'])) {
6342
		$ifaces = array();
6343
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
6344
			if ($int == $qinq['if']) {
6345
				if ($action == "update") {
6346
					interfaces_bring_up($int);
6347
				} else {
6348
					$ifaces[$qinq['tag']] = $qinq;
6349
				}
6350
			}
6351
		}
6352
		if (!empty($ifaces)) {
6353
			return $ifaces;
6354
		}
6355
	}
6356
}
6357

    
6358
function link_interface_to_vips($int, $action = "", $vhid = '') {
6359
	global $config;
6360

    
6361
	$updatevips = false;
6362
	if (is_array($config['virtualip']['vip'])) {
6363
		$result = array();
6364
		foreach ($config['virtualip']['vip'] as $vip) {
6365
			if (substr($vip['interface'], 0, 4) == "_vip") {
6366
				$iface = get_configured_vip_interface($vip['interface']);
6367
			} else {
6368
				$iface = $vip['interface'];
6369
			}
6370
			if ($int != $iface) {
6371
				continue;
6372
			}
6373
			if ($action == "update") {
6374
				$updatevips = true;
6375
			} else {
6376
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
6377
				    substr($vip['interface'], 0, 4) == "_vip") {
6378
					$result[] = $vip;
6379
				}
6380
			}
6381
		}
6382
		if ($updatevips === true) {
6383
			interfaces_vips_configure($int);
6384
		}
6385
		return $result;
6386
	}
6387

    
6388
	return NULL;
6389
}
6390

    
6391
/****f* interfaces/link_interface_to_bridge
6392
 * NAME
6393
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6394
 * INPUTS
6395
 *   $ip
6396
 * RESULT
6397
 *   bridge[0-99]
6398
 ******/
6399
function link_interface_to_bridge($int) {
6400
	global $config;
6401

    
6402
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged'])) {
6403
		foreach ($config['bridges']['bridged'] as $bridge) {
6404
			if (in_array($int, explode(',', $bridge['members']))) {
6405
				return "{$bridge['bridgeif']}";
6406
			}
6407
		}
6408
	}
6409
}
6410

    
6411
function link_interface_to_lagg($int) {
6412
	global $config;
6413

    
6414
	if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
6415
		foreach ($config['laggs']['lagg'] as $lagg) {
6416
			if (in_array($int, explode(',', $lagg['members']))) {
6417
				return "{$lagg['laggif']}";
6418
			}
6419
		}
6420
	}
6421
}
6422

    
6423
function link_interface_to_group($int) {
6424
	global $config;
6425

    
6426
	$result = array();
6427

    
6428
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
6429
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
6430
			if (in_array($int, explode(" ", $group['members']))) {
6431
				$result[$group['ifname']] = $int;
6432
			}
6433
		}
6434
	}
6435

    
6436
	return $result;
6437
}
6438

    
6439
function link_interface_to_tunnelif($interface, $type) {
6440
	global $config;
6441

    
6442
	if (!in_array($type, array('gre', 'gif'))) {
6443
		return;
6444
	}
6445

    
6446
	$result = array();
6447

    
6448
	if (is_array($config["{$type}s"][$type])) {
6449
		foreach ($config["{$type}s"][$type] as $tunnel) {
6450
			if ($tunnel['if'] == $interface) {
6451
				$result[] = $tunnel;
6452
			}
6453
		}
6454
	}
6455

    
6456
	return $result;
6457
}
6458

    
6459
/*
6460
 * find_interface_ip($interface): return the interface ip (first found)
6461
 */
6462
function find_interface_ip($interface, $flush = false) {
6463
	global $interface_ip_arr_cache;
6464
	global $interface_sn_arr_cache;
6465

    
6466
	$interface = str_replace("\n", "", $interface);
6467

    
6468
	if (!does_interface_exist($interface)) {
6469
		return;
6470
	}
6471

    
6472
	/* Setup IP cache */
6473
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6474
		if (file_exists("/var/db/${interface}_ip")) {
6475
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6476
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6477
			foreach ($ifaddrs as $ifaddr) {
6478
				list($ip, $mask) = explode("/", $ifaddr);
6479
				if ($ip == $ifip) {
6480
					$interface_ip_arr_cache[$interface] = $ip;
6481
					$interface_sn_arr_cache[$interface] = $mask;
6482
					break;
6483
				}
6484
			}
6485
		}
6486
		if (!isset($interface_ip_arr_cache[$interface])) {
6487
			$ifinfo = pfSense_get_interface_addresses($interface);
6488
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6489
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6490
		}
6491
	}
6492

    
6493
	return $interface_ip_arr_cache[$interface];
6494
}
6495

    
6496
/*
6497
 * find_interface_ipv6($interface): return the interface ip (first found)
6498
 */
6499
function find_interface_ipv6($interface, $flush = false) {
6500
	global $interface_ipv6_arr_cache;
6501
	global $interface_snv6_arr_cache;
6502
	global $config;
6503

    
6504
	$interface = trim($interface);
6505
	$interface = get_real_interface($interface);
6506

    
6507
	if (!does_interface_exist($interface)) {
6508
		return;
6509
	}
6510

    
6511
	/* Setup IP cache */
6512
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6513
		$ifinfo = pfSense_get_interface_addresses($interface);
6514
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6515
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6516
	}
6517

    
6518
	return $interface_ipv6_arr_cache[$interface];
6519
}
6520

    
6521
/*
6522
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6523
 */
6524
function find_interface_ipv6_ll($interface, $flush = false) {
6525
	global $interface_llv6_arr_cache;
6526
	global $config;
6527

    
6528
	$interface = str_replace("\n", "", $interface);
6529

    
6530
	if (!does_interface_exist($interface)) {
6531
		return;
6532
	}
6533

    
6534
	/* Setup IP cache */
6535
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6536
		$ifinfo = pfSense_getall_interface_addresses($interface);
6537
		foreach ($ifinfo as $line) {
6538
			if (strstr($line, ":")) {
6539
				$parts = explode("/", $line);
6540
				if (is_linklocal($parts[0])) {
6541
					$ifinfo['linklocal'] = $parts[0];
6542
				}
6543
			}
6544
		}
6545
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6546
	}
6547
	return $interface_llv6_arr_cache[$interface];
6548
}
6549

    
6550
function find_interface_subnet($interface, $flush = false) {
6551
	global $interface_sn_arr_cache;
6552
	global $interface_ip_arr_cache;
6553

    
6554
	$interface = str_replace("\n", "", $interface);
6555
	if (does_interface_exist($interface) == false) {
6556
		return;
6557
	}
6558

    
6559
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6560
		$ifinfo = pfSense_get_interface_addresses($interface);
6561
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6562
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6563
	}
6564

    
6565
	return $interface_sn_arr_cache[$interface];
6566
}
6567

    
6568
function find_interface_subnetv6($interface, $flush = false) {
6569
	global $interface_snv6_arr_cache;
6570
	global $interface_ipv6_arr_cache;
6571

    
6572
	$interface = str_replace("\n", "", $interface);
6573
	if (does_interface_exist($interface) == false) {
6574
		return;
6575
	}
6576

    
6577
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6578
		$ifinfo = pfSense_get_interface_addresses($interface);
6579
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6580
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6581
	}
6582

    
6583
	return $interface_snv6_arr_cache[$interface];
6584
}
6585

    
6586
function ip_in_interface_alias_subnet($interface, $ipalias) {
6587
	global $config;
6588

    
6589
	if (empty($interface) || !is_ipaddr($ipalias)) {
6590
		return false;
6591
	}
6592
	if (is_array($config['virtualip']['vip'])) {
6593
		foreach ($config['virtualip']['vip'] as $vip) {
6594
			switch ($vip['mode']) {
6595
				case "ipalias":
6596
					if ($vip['interface'] <> $interface) {
6597
						break;
6598
					}
6599
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6600
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6601
						return true;
6602
					}
6603
					break;
6604
			}
6605
		}
6606
	}
6607

    
6608
	return false;
6609
}
6610

    
6611
function get_possible_listen_ips($include_ipv6_link_local=false) {
6612

    
6613
	$interfaces = get_configured_interface_with_descr();
6614
	foreach ($interfaces as $iface => $ifacename) {
6615
		if ($include_ipv6_link_local) {
6616
			/* This is to avoid going though added ll below */
6617
			if (substr($iface, 0, 5) == '_lloc') {
6618
				continue;
6619
			}
6620
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6621
			if (!empty($llip)) {
6622
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6623
			}
6624
		}
6625
	}
6626
	$viplist = get_configured_vip_list();
6627
	foreach ($viplist as $vip => $address) {
6628
		$interfaces[$vip] = $address;
6629
		if (get_vip_descr($address)) {
6630
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6631
		}
6632
	}
6633

    
6634
	$interfaces['lo0'] = 'Localhost';
6635

    
6636
	return $interfaces;
6637
}
6638

    
6639
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6640
	global $config;
6641

    
6642
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6643
	foreach (array('server', 'client') as $mode) {
6644
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
6645
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
6646
				if (!isset($setting['disable'])) {
6647
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6648
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6649
				}
6650
			}
6651
		}
6652
	}
6653
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
6654
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
6655
			if ($ph1ent['disabled']) {
6656
				continue;
6657
			}
6658
			if (ipsec_vti($ph1ent)) {
6659
				$sourceips_key = "ipsec{$ph1ent['ikeid']}";
6660
				$sourceips[$sourceips_key] = gettext("IPsec VTI") . ": " . htmlspecialchars($ph1ent['descr']);
6661
			}
6662
		}
6663
	}
6664
	return $sourceips;
6665
}
6666

    
6667
function get_interface_ip($interface = "wan") {
6668
	global $config;
6669

    
6670
	if (substr($interface, 0, 4) == '_vip') {
6671
		return get_configured_vip_ipv4($interface);
6672
	} elseif (substr($interface, 0, 5) == '_lloc') {
6673
		/* No link-local address for v4. */
6674
		return null;
6675
	}
6676

    
6677
	$realif = get_failover_interface($interface, 'inet');
6678
	if (!$realif) {
6679
		return null;
6680
	}
6681

    
6682
	if (substr($realif, 0, 4) == '_vip') {
6683
		return get_configured_vip_ipv4($realif);
6684
	} elseif (substr($realif, 0, 5) == '_lloc') {
6685
		/* No link-local address for v4. */
6686
		return null;
6687
	}
6688

    
6689
	if (is_array($config['interfaces'][$interface]) &&
6690
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6691
		return ($config['interfaces'][$interface]['ipaddr']);
6692
	}
6693

    
6694
	/*
6695
	 * Beaware that find_interface_ip() is our last option, it will
6696
	 * return the first IP it find on interface, not necessarily the
6697
	 * main IP address.
6698
	 */
6699
	$curip = find_interface_ip($realif);
6700
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6701
		return $curip;
6702
	} else {
6703
		return null;
6704
	}
6705
}
6706

    
6707
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6708
	global $config;
6709

    
6710
	if (substr($interface, 0, 4) == '_vip') {
6711
		return get_configured_vip_ipv6($interface);
6712
	} elseif (substr($interface, 0, 5) == '_lloc') {
6713
		return get_interface_linklocal($interface);
6714
	}
6715

    
6716
	$realif = get_failover_interface($interface, 'inet6');
6717
	if (!$realif) {
6718
		return null;
6719
	}
6720

    
6721
	if (substr($realif, 0, 4) == '_vip') {
6722
		return get_configured_vip_ipv6($realif);
6723
	} elseif (substr($realif, 0, 5) == '_lloc') {
6724
		return get_interface_linklocal($realif);
6725
	}
6726

    
6727
	if (is_array($config['interfaces'][$interface])) {
6728
		switch ($config['interfaces'][$interface]['ipaddr']) {
6729
			case 'pppoe':
6730
			case 'l2tp':
6731
			case 'pptp':
6732
			case 'ppp':
6733
				if (($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') ||
6734
				    ($config['interfaces'][$interface]['ipaddrv6'] == 'slaac')) {
6735
					$realif = get_real_interface($interface, 'inet6', false);
6736
				}
6737
				break;
6738
		}
6739
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6740
			return ($config['interfaces'][$interface]['ipaddrv6']);
6741
		}
6742
	}
6743

    
6744
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6745
	if ($config['interfaces'][$interface]['ipaddrv6'] == 'track6') {
6746
		$curip = get_interface_track6ip($interface);
6747
		if ($curip) {
6748
			return $curip[0];
6749
		}
6750
	}
6751

    
6752
	/*
6753
	 * Beaware that find_interface_ip() is our last option, it will
6754
	 * return the first IP it find on interface, not necessarily the
6755
	 * main IP address.
6756
	 */
6757
	$curip = find_interface_ipv6($realif, $flush);
6758
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6759
		return $curip;
6760
	} else {
6761
		/*
6762
		 * NOTE: On the case when only the prefix is requested,
6763
		 * the communication on WAN will be done over link-local.
6764
		 */
6765
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6766
			$curip = find_interface_ipv6_ll($realif, $flush);
6767
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6768
				return $curip;
6769
			}
6770
		}
6771
	}
6772
	return null;
6773
}
6774

    
6775
function get_interface_linklocal($interface = "wan") {
6776

    
6777
	$realif = get_failover_interface($interface, 'inet6');
6778
	if (!$realif) {
6779
		return null;
6780
	}
6781

    
6782
	if (substr($interface, 0, 4) == '_vip') {
6783
		$realif = get_real_interface($interface);
6784
	} elseif (substr($interface, 0, 5) == '_lloc') {
6785
		$realif = get_real_interface(substr($interface, 5));
6786
	}
6787

    
6788
	$curip = find_interface_ipv6_ll($realif);
6789
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6790
		return $curip;
6791
	} else {
6792
		return null;
6793
	}
6794
}
6795

    
6796
function get_interface_track6ip($interface = "wan") {
6797
	$realif = get_real_interface($interface);
6798
	$vips = get_configured_vip_list('inet6');
6799

    
6800
	foreach (pfSense_getall_interface_addresses($realif) as $ifaddr) {
6801
		list($ip, $bits) = explode("/", $ifaddr);
6802
		$ip = text_to_compressed_ip6($ip);
6803
		if (is_ipaddrv6($ip) && !is_linklocal($ip)) {
6804
			if (is_array($vips) && !empty($vips)) {
6805
				foreach ($vips as $vip) {
6806
					if ($ip == text_to_compressed_ip6($vip)) {
6807
						continue 2;
6808
					}
6809
				}
6810
			}
6811
			return array($ip, $bits);
6812
		}
6813
	}
6814
	return false;
6815
}
6816

    
6817
function get_interface_subnet($interface = "wan") {
6818
	global $config;
6819

    
6820
	if (substr($interface, 0, 4) == '_vip') {
6821
		return (get_configured_vip_subnetv4($interface));
6822
	}
6823

    
6824
	if (is_array($config['interfaces'][$interface]) &&
6825
	    !empty($config['interfaces'][$interface]['subnet']) &&
6826
	    is_ipaddrv4($config['interfaces'][$interface]['ipaddr'])) {
6827
		return ($config['interfaces'][$interface]['subnet']);
6828
	}
6829

    
6830
	$realif = get_real_interface($interface);
6831
	if (!$realif) {
6832
		return (NULL);
6833
	}
6834

    
6835
	$cursn = find_interface_subnet($realif);
6836
	if (!empty($cursn)) {
6837
		return ($cursn);
6838
	}
6839

    
6840
	return (NULL);
6841
}
6842

    
6843
function get_interface_subnetv6($interface = "wan") {
6844
	global $config;
6845

    
6846
	if (substr($interface, 0, 4) == '_vip') {
6847
		return (get_configured_vip_subnetv6($interface));
6848
	} elseif (substr($interface, 0, 5) == '_lloc') {
6849
		$interface = substr($interface, 5);
6850
	}
6851

    
6852
	if (is_array($config['interfaces'][$interface]) &&
6853
	    !empty($config['interfaces'][$interface]['subnetv6']) &&
6854
	    is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6855
		return ($config['interfaces'][$interface]['subnetv6']);
6856
	}
6857

    
6858
	$realif = get_real_interface($interface, 'inet6');
6859
	if (!$realif) {
6860
		return (NULL);
6861
	}
6862

    
6863
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6864
	if ($config['interfaces'][$interface]['ipaddrv6'] == 'track6') {
6865
		$curip = get_interface_track6ip($interface);
6866
		if ($curip) {
6867
			return $curip[1];
6868
		}
6869
	}
6870

    
6871
	$cursn = find_interface_subnetv6($realif);
6872
	if (!empty($cursn)) {
6873
		return ($cursn);
6874
	}
6875

    
6876
	return (NULL);
6877
}
6878

    
6879
/* return outside interfaces with a gateway */
6880
function get_interfaces_with_gateway() {
6881
	global $config;
6882

    
6883
	$ints = array();
6884

    
6885
	/* loop interfaces, check config for outbound */
6886
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6887
		switch ($ifname['ipaddr']) {
6888
			case "dhcp":
6889
			case "pppoe":
6890
			case "pptp":
6891
			case "l2tp":
6892
			case "ppp":
6893
				$ints[$ifdescr] = $ifdescr;
6894
				break;
6895
			default:
6896
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6897
				    !empty($ifname['gateway'])) {
6898
					$ints[$ifdescr] = $ifdescr;
6899
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6900
				    !empty($ifname['gateway'])) {
6901
					$ints[$ifdescr] = $ifdescr;
6902
				}
6903

    
6904
				break;
6905
		}
6906
	}
6907
	return $ints;
6908
}
6909

    
6910
/* return true if interface has a gateway */
6911
function interface_has_gateway($friendly) {
6912
	global $config;
6913

    
6914
	if (!empty($config['interfaces'][$friendly])) {
6915
		$ifname = &$config['interfaces'][$friendly];
6916
		switch ($ifname['ipaddr']) {
6917
			case "dhcp":
6918
				/* see https://redmine.pfsense.org/issues/5135 */
6919
				if (get_interface_gateway($friendly)) {
6920
					return true;
6921
				}
6922
				break;
6923
			case "pppoe":
6924
			case "pptp":
6925
			case "l2tp":
6926
			case "ppp":
6927
				return true;
6928
				break;
6929
			default:
6930
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6931
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6932
					return true;
6933
				}
6934
				$tunnelif = substr($ifname['if'], 0, 3);
6935
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6936
					if (find_interface_ip($ifname['if'])) {
6937
						return true;
6938
					}
6939
				}
6940
				if (!empty($ifname['gateway'])) {
6941
					return true;
6942
				}
6943
				break;
6944
		}
6945
	}
6946

    
6947
	return false;
6948
}
6949

    
6950
/* return true if interface has a gateway */
6951
function interface_has_gatewayv6($friendly) {
6952
	global $config;
6953

    
6954
	if (!empty($config['interfaces'][$friendly])) {
6955
		$ifname = &$config['interfaces'][$friendly];
6956
		switch ($ifname['ipaddrv6']) {
6957
			case "slaac":
6958
			case "dhcp6":
6959
			case "6to4":
6960
			case "6rd":
6961
				return true;
6962
				break;
6963
			default:
6964
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6965
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6966
					return true;
6967
				}
6968
				$tunnelif = substr($ifname['if'], 0, 3);
6969
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6970
					if (find_interface_ipv6($ifname['if'])) {
6971
						return true;
6972
					}
6973
				}
6974
				if (!empty($ifname['gatewayv6'])) {
6975
					return true;
6976
				}
6977
				break;
6978
		}
6979
	}
6980

    
6981
	return false;
6982
}
6983

    
6984
/****f* interfaces/is_altq_capable
6985
 * NAME
6986
 *   is_altq_capable - Test if interface is capable of using ALTQ
6987
 * INPUTS
6988
 *   $int            - string containing interface name
6989
 * RESULT
6990
 *   boolean         - true or false
6991
 ******/
6992

    
6993
function is_altq_capable($int) {
6994
	/* Per:
6995
	 * http://www.freebsd.org/cgi/man.cgi?query=altq&apropos=0&sektion=0&manpath=FreeBSD+11.0-RELEASE&arch=default&format=html
6996
	 * Only the following drivers have ALTQ support
6997
	 * 20150328 - removed wireless drivers - ath, awi, bwn, iwi, ipw, ral, rum, run, wi - for now. redmine #4406
6998
	 */
6999
	$capable = array("ae", "age", "alc", "ale", "an", "aue", "axe", "bce",
7000
			"bfe", "bge", "bnxt", "bridge", "cas", "cpsw", "cxl", "dc", "de",
7001
			"ed", "em", "ep", "epair", "et", "fxp", "gem", "hme", "hn",
7002
			"igb", "igc", "ix", "jme", "l2tp", "le", "lem", "msk", "mxge", "my",
7003
			"ndis", "nfe", "ng", "nge", "npe", "nve", "ql", "ovpnc",
7004
			"ovpns", "ppp", "pppoe", "pptp", "re", "rl", "sf", "sge",
7005
			"sis", "sk", "ste", "stge", "ti", "tun", "txp", "udav",
7006
			"ural", "vge", "vlan", "vmx", "vr", "vte", "vtnet", "xl");
7007

    
7008
	$int_family = remove_ifindex($int);
7009

    
7010
	if (in_array($int_family, $capable)) {
7011
		return true;
7012
	} elseif (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
7013
		return true;
7014
	} elseif (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
7015
		return true;
7016
	} elseif (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
7017
		return true;
7018
	} else {
7019
		return false;
7020
	}
7021
}
7022

    
7023
/****f* interfaces/is_interface_wireless
7024
 * NAME
7025
 *   is_interface_wireless - Returns if an interface is wireless
7026
 * RESULT
7027
 *   $tmp       - Returns if an interface is wireless
7028
 ******/
7029
function is_interface_wireless($interface) {
7030
	global $config, $g;
7031

    
7032
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
7033
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
7034
		if (preg_match($g['wireless_regex'], $interface)) {
7035
			if (isset($config['interfaces'][$friendly])) {
7036
				$config['interfaces'][$friendly]['wireless'] = array();
7037
			}
7038
			return true;
7039
		}
7040
		return false;
7041
	} else {
7042
		return true;
7043
	}
7044
}
7045

    
7046
function get_wireless_modes($interface) {
7047
	/* return wireless modes and channels */
7048
	$wireless_modes = array();
7049

    
7050
	$cloned_interface = get_real_interface($interface);
7051

    
7052
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7053
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
7054
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
7055
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
7056

    
7057
		$interface_channels = "";
7058
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
7059
		$interface_channel_count = count($interface_channels);
7060

    
7061
		$c = 0;
7062
		while ($c < $interface_channel_count) {
7063
			$channel_line = explode(",", $interface_channels["$c"]);
7064
			$wireless_mode = trim($channel_line[0]);
7065
			$wireless_channel = trim($channel_line[1]);
7066
			if (trim($wireless_mode) != "") {
7067
				/* if we only have 11g also set 11b channels */
7068
				if ($wireless_mode == "11g") {
7069
					if (!isset($wireless_modes["11b"])) {
7070
						$wireless_modes["11b"] = array();
7071
					}
7072
				} elseif ($wireless_mode == "11g ht") {
7073
					if (!isset($wireless_modes["11b"])) {
7074
						$wireless_modes["11b"] = array();
7075
					}
7076
					if (!isset($wireless_modes["11g"])) {
7077
						$wireless_modes["11g"] = array();
7078
					}
7079
					$wireless_mode = "11ng";
7080
				} elseif ($wireless_mode == "11a ht") {
7081
					if (!isset($wireless_modes["11a"])) {
7082
						$wireless_modes["11a"] = array();
7083
					}
7084
					$wireless_mode = "11na";
7085
				}
7086
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
7087
			}
7088
			$c++;
7089
		}
7090
	}
7091
	return($wireless_modes);
7092
}
7093

    
7094
function get_wireless_channels($interface) {
7095
		$chan_list = "/sbin/ifconfig -v " . escapeshellarg($interface) . " list chan";
7096
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
7097
		$format_list = "/usr/bin/awk '{print \$5 \",\" \$6 \",\" \$1}'";
7098

    
7099
		$interface_channels = "";
7100
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7101
		return $interface_channels;
7102
}
7103

    
7104
/* return wireless HT modes */
7105
function get_wireless_ht_modes($interface) {
7106
	$wireless_hts_supported = array(0 => gettext('Auto'));
7107

    
7108
	$cloned_interface = get_real_interface($interface);
7109

    
7110
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7111
		$interface_channels = get_wireless_channels($cloned_interface);
7112

    
7113
		foreach ($interface_channels as $channel) {
7114
			$channel_line = explode(",", $channel);
7115
			$wireless_ht = trim($channel_line[1]);
7116
			if (!empty($wireless_ht)) {
7117
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
7118
			}
7119
		}
7120
	}
7121
	return($wireless_hts_supported);
7122
}
7123

    
7124
/* return wireless HT by channel/standard */
7125
function get_wireless_ht_list($interface) {
7126
	$wireless_hts = array();
7127

    
7128
	$cloned_interface = get_real_interface($interface);
7129

    
7130
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7131
		$interface_channels = get_wireless_channels($cloned_interface);
7132
		$interface_channel_count = count($interface_channels);
7133

    
7134
		$c = 0;
7135
		while ($c < $interface_channel_count) {
7136
			$channel_line = explode(",", $interface_channels["$c"]);
7137
			$wireless_mode = trim($channel_line[0]);
7138
			$wireless_ht = trim($channel_line[1]);
7139
			$wireless_channel = trim($channel_line[2]);
7140
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
7141
				if ($wireless_mode == "11g") {
7142
					if (!isset($wireless_modes["11g"])) {
7143
						$wireless_hts["11g"] = array();
7144
					}
7145
					$wireless_mode = "11ng";
7146
				} elseif ($wireless_mode == "11a") {
7147
					if (!isset($wireless_modes["11a"])) {
7148
						$wireless_hts["11a"] = array();
7149
					}
7150
					$wireless_mode = "11na";
7151
				}
7152
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
7153
			}
7154
			$c++;
7155
		}
7156
	}
7157
	return($wireless_hts);
7158
}
7159

    
7160
/* return channel numbers, frequency, max txpower, and max regulation txpower */
7161
function get_wireless_channel_info($interface) {
7162
	$wireless_channels = array();
7163

    
7164
	$cloned_interface = get_real_interface($interface);
7165

    
7166
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7167
		$chan_list = "/sbin/ifconfig " . escapeshellarg($cloned_interface) . " list txpower";
7168
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
7169
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
7170

    
7171
		$interface_channels = "";
7172
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7173

    
7174
		foreach ($interface_channels as $channel_line) {
7175
			$channel_line = explode(",", $channel_line);
7176
			if (!isset($wireless_channels[$channel_line[0]])) {
7177
				$wireless_channels[$channel_line[0]] = $channel_line;
7178
			}
7179
		}
7180
	}
7181
	return($wireless_channels);
7182
}
7183

    
7184
function set_interface_mtu($interface, $mtu) {
7185

    
7186
	/* LAGG interface must be destroyed and re-created to change MTU */
7187
	if ((substr($interface, 0, 4) == 'lagg') &&
7188
	    (!strstr($interface, "."))) {
7189
		if (isset($config['laggs']['lagg']) &&
7190
		    is_array($config['laggs']['lagg'])) {
7191
			foreach ($config['laggs']['lagg'] as $lagg) {
7192
				if ($lagg['laggif'] == $interface) {
7193
					interface_lagg_configure($lagg);
7194
					break;
7195
				}
7196
			}
7197
		}
7198
	} else {
7199
		pfSense_interface_mtu($interface, $mtu);
7200
		set_ipv6routes_mtu($interface, $mtu);
7201
	}
7202
}
7203

    
7204
/****f* interfaces/get_interface_mtu
7205
 * NAME
7206
 *   get_interface_mtu - Return the mtu of an interface
7207
 * RESULT
7208
 *   $tmp       - Returns the mtu of an interface
7209
 ******/
7210
function get_interface_mtu($interface) {
7211
	$mtu = pfSense_interface_getmtu($interface);
7212
	return $mtu['mtu'];
7213
}
7214

    
7215
function get_interface_mac($interface) {
7216
	$macinfo = pfSense_get_interface_addresses($interface);
7217
	return $macinfo["macaddr"];
7218
}
7219

    
7220
function get_interface_vendor_mac($interface) {
7221
	global $config, $g;
7222

    
7223
	$macinfo = pfSense_get_interface_addresses($interface);
7224
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7225
	    "00:00:00:00:00:00") {
7226
		return ($macinfo["hwaddr"]);
7227
	}
7228

    
7229
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7230
	if (file_exists($hwaddr_file)) {
7231
		$macaddr = trim(file_get_contents($hwaddr_file));
7232
		if (is_macaddr($macaddr)) {
7233
			return ($macaddr);
7234
		}
7235
	} elseif (is_macaddr($macinfo['macaddr'])) {
7236
		/* Save original macaddress to be restored when necessary */
7237
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7238
	}
7239

    
7240
	return (NULL);
7241
}
7242

    
7243
/****f* pfsense-utils/generate_random_mac_address
7244
 * NAME
7245
 *   generate_random_mac - generates a random mac address
7246
 * INPUTS
7247
 *   none
7248
 * RESULT
7249
 *   $mac - a random mac address
7250
 ******/
7251
function generate_random_mac_address() {
7252
	$mac = "02";
7253
	for ($x = 0; $x < 5; $x++) {
7254
		$mac .= ":" . dechex(rand(16, 255));
7255
	}
7256
	return $mac;
7257
}
7258

    
7259
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7260
	global $g;
7261

    
7262
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7263

    
7264
	if (!empty($iface) && !empty($pppif)) {
7265
		$cron_cmd = <<<EOD
7266
#!/bin/sh
7267
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7268
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7269

    
7270
EOD;
7271

    
7272
		@file_put_contents($cron_file, $cron_cmd);
7273
		chmod($cron_file, 0755);
7274
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7275
	} else {
7276
		unlink_if_exists($cron_file);
7277
	}
7278
}
7279

    
7280
function get_interface_default_mtu($type = "ethernet") {
7281
	switch ($type) {
7282
		case "gre":
7283
			return 1476;
7284
			break;
7285
		case "gif":
7286
			return 1280;
7287
			break;
7288
		case "tun":
7289
		case "vlan":
7290
		case "tap":
7291
		case "ethernet":
7292
		default:
7293
			return 1500;
7294
			break;
7295
	}
7296

    
7297
	/* Never reached */
7298
	return 1500;
7299
}
7300

    
7301
function get_vip_descr($ipaddress) {
7302
	global $config;
7303

    
7304
	foreach ($config['virtualip']['vip'] as $vip) {
7305
		if ($vip['subnet'] == $ipaddress) {
7306
			return ($vip['descr']);
7307
		}
7308
	}
7309
	return "";
7310
}
7311

    
7312
function interfaces_staticarp_configure($if) {
7313
	global $config, $g;
7314
	if (isset($config['system']['developerspew'])) {
7315
		$mt = microtime();
7316
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7317
	}
7318

    
7319
	$ifcfg = $config['interfaces'][$if];
7320

    
7321
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
7322
		return 0;
7323
	}
7324

    
7325
	/* Enable staticarp, if enabled */
7326
	if (isset($config['dhcpd'][$if]['staticarp'])) {
7327
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7328
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7329
	} else {
7330
		/*
7331
		 * Interfaces do not have staticarp enabled by default
7332
		 * Let's not disable staticarp on freshly created interfaces
7333
		 */
7334
		if (!platform_booting()) {
7335
			mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7336
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7337
		}
7338
	}
7339

    
7340
	/* Enable static arp entries */
7341
	if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
7342
		foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
7343
			if (empty($arpent['ipaddr']) || empty($arpent['mac'])) {
7344
				continue;
7345
			}
7346
			if (isset($config['dhcpd'][$if]['staticarp']) || isset($arpent['arp_table_static_entry'])) {
7347
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7348
			}
7349
		}
7350
	}
7351

    
7352
	return 0;
7353
}
7354

    
7355
function get_failover_interface($interface, $family = "all") {
7356
	global $config;
7357

    
7358
	/* shortcut to get_real_interface if we find it in the config */
7359
	if (is_array($config['interfaces'][$interface])) {
7360
		return get_real_interface($interface, $family);
7361
	}
7362

    
7363
	/* compare against gateway groups */
7364
	$a_groups = return_gateway_groups_array(true);
7365
	if (is_array($a_groups[$interface])) {
7366
		/* we found a gateway group, fetch the interface or vip */
7367
		if (!empty($a_groups[$interface][0]['vip'])) {
7368
			return $a_groups[$interface][0]['vip'];
7369
		} else {
7370
			return $a_groups[$interface][0]['int'];
7371
		}
7372
	}
7373
	/* fall through to get_real_interface */
7374
	/* XXX: Really needed? */
7375
	return get_real_interface($interface, $family);
7376
}
7377

    
7378
/****f* interfaces/interface_has_dhcp
7379
 * NAME
7380
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7381
 * INPUTS
7382
 *   interface or gateway group name
7383
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7384
 * RESULT
7385
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7386
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7387
 ******/
7388
function interface_has_dhcp($interface, $family = 4) {
7389
	global $config;
7390

    
7391
	if ($config['interfaces'][$interface]) {
7392
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
7393
			return true;
7394
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
7395
			return true;
7396
		} else {
7397
			return false;
7398
		}
7399
	}
7400

    
7401
	if (!is_array($config['gateways']['gateway_group'])) {
7402
		return false;
7403
	}
7404

    
7405
	if ($family == 6) {
7406
		$dhcp_string = "_DHCP6";
7407
	} else {
7408
		$dhcp_string = "_DHCP";
7409
	}
7410

    
7411
	foreach ($config['gateways']['gateway_group'] as $group) {
7412
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7413
			continue;
7414
		}
7415
		foreach ($group['item'] as $item) {
7416
			$item_data = explode("|", $item);
7417
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7418
				return true;
7419
			}
7420
		}
7421
	}
7422

    
7423
	return false;
7424
}
7425

    
7426
function remove_ifindex($ifname) {
7427
	return preg_replace("/[0-9]+$/", "", $ifname);
7428
}
7429

    
7430
function get_configured_vip_list_with_descr($family = 'all', $type = VIP_ALL) {
7431
	$interfaces = array();	// In case there are no VIPs defined
7432

    
7433
	$viplist = get_configured_vip_list($family, $type);
7434
	foreach ($viplist as $vip => $address) {
7435
		$interfaces[$vip] = $address;
7436
		if ($type = VIP_CARP) {
7437
			$vip = get_configured_vip($vipid);
7438
			if (isset($vip) && is_array($vip) ) {
7439
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7440
			}
7441
		}
7442
		if (get_vip_descr($address)) {
7443
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
7444
		}
7445
	}
7446
	return $interfaces;
7447
}
7448

    
7449
function return_gateway_groups_array_with_descr() {
7450
	$interfaces = array();
7451
	$grouplist = return_gateway_groups_array();
7452
	foreach ($grouplist as $name => $group) {
7453
		if ($group[0]['vip'] != "") {
7454
			$vipif = $group[0]['vip'];
7455
		} else {
7456
			$vipif = $group[0]['int'];
7457
		}
7458

    
7459
		$interfaces[$name] = "GW Group {$name}";
7460
	}
7461
	return $interfaces;
7462
}
7463

    
7464
function get_serial_ports() {
7465
	$linklist = array();
7466
	if (!is_dir("/var/spool/lock")) {
7467
		mwexec("/bin/mkdir -p /var/spool/lock");
7468
	}
7469
	$serialports = glob("/dev/cua[a-zA-Z][0-9]{,.[0-9],.[0-9][0-9],[0-9],[0-9].[0-9],[0-9].[0-9][0-9]}", GLOB_BRACE);
7470
	foreach ($serialports as $port) {
7471
		$linklist[$port] = trim($port);
7472
	}
7473
	return $linklist;
7474
}
7475

    
7476
function get_interface_ports() {
7477
	global $config;
7478
	$linklist = array();
7479
	$portlist = get_interface_list();
7480
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
7481
		foreach ($config['vlans']['vlan'] as $vlan) {
7482
			$portlist[$vlan['vlanif']] = $vlan;
7483
		}
7484
	}
7485

    
7486
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
7487
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
7488
			$members = explode(" ", $qinq['members']);
7489
			foreach ($members as $mem) {
7490
				$qentry = $qinq['vlanif'] . "." . $mem;
7491
				$portlist[$qentry] = $qentry;
7492
			}
7493
		}
7494
	}
7495

    
7496
	foreach ($portlist as $ifn => $ifinfo) {
7497
		$string = "";
7498
		if (is_array($ifinfo)) {
7499
			$string .= $ifn;
7500
			if ($ifinfo['mac']) {
7501
				$string .= " ({$ifinfo['mac']})";
7502
			}
7503
			if ($ifinfo['friendly']) {
7504
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7505
			} elseif ($ifinfo['descr']) {
7506
				$string .= " - {$ifinfo['descr']}";
7507
			}
7508
		} else {
7509
			$string .= $ifinfo;
7510
		}
7511

    
7512
		$linklist[$ifn] = $string;
7513
	}
7514
	return $linklist;
7515
}
7516

    
7517
function build_ppps_link_list() {
7518
	global $pconfig;
7519

    
7520
	$linklist = array('list' => array(), 'selected' => array());
7521

    
7522
	if ($pconfig['type'] == 'ppp') {
7523
		$linklist['list'] = get_serial_ports();
7524
	} else {
7525
		$iflist = get_interface_ports();
7526

    
7527
		$viplist = array();
7528
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7529
		foreach ($carplist as $vid => $vaddr) {
7530
			$vip = get_configured_vip($vid);
7531
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7532
		}
7533

    
7534
		$linklist['list'] = array_merge($iflist, $viplist);
7535

    
7536
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7537
		$lagglist = get_lagg_interface_list();
7538
		foreach ($lagglist as $laggif => $lagg) {
7539
			/* LAGG members cannot be assigned */
7540
			$laggmembers = explode(',', $lagg['members']);
7541
			foreach ($laggmembers as $lagm) {
7542
				if (isset($linklist['list'][$lagm])) {
7543
					unset($linklist['list'][$lagm]);
7544
				}
7545
			}
7546
		}
7547
	}
7548

    
7549
	$selected_ports = array();
7550
	if (is_array($pconfig['interfaces'])) {
7551
		$selected_ports = $pconfig['interfaces'];
7552
	} elseif (!empty($pconfig['interfaces'])) {
7553
		$selected_ports = explode(',', $pconfig['interfaces']);
7554
	}
7555
	foreach ($selected_ports as $port) {
7556
		if (isset($linklist['list'][$port])) {
7557
			array_push($linklist['selected'], $port);
7558
		}
7559
	}
7560
	return($linklist);
7561
}
7562

    
7563
function create_interface_list($open = false) {
7564
	global $config;
7565

    
7566
	$iflist = array();
7567

    
7568
	// add group interfaces
7569
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
7570
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
7571
			if ($open || have_ruleint_access($ifgen['ifname'])) {
7572
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7573
			}
7574
		}
7575
	}
7576

    
7577
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7578
		if ($open || have_ruleint_access($ifent)) {
7579
			$iflist[$ifent] = $ifdesc;
7580
		}
7581
	}
7582

    
7583
	if ($config['l2tp']['mode'] == "server" && ($open || have_ruleint_access("l2tp"))) {
7584
		$iflist['l2tp'] = gettext('L2TP VPN');
7585
	}
7586

    
7587
	if (is_pppoe_server_enabled() && ($open || have_ruleint_access("pppoe"))) {
7588
		$iflist['pppoe'] = gettext("PPPoE Server");
7589
	}
7590

    
7591
	// add ipsec interfaces
7592
	if (ipsec_enabled() && ($open || have_ruleint_access("enc0"))) {
7593
		$iflist["enc0"] = gettext("IPsec");
7594
	}
7595

    
7596
	// add openvpn/tun interfaces
7597
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7598
		$iflist["openvpn"] = gettext("OpenVPN");
7599
	}
7600

    
7601
	return($iflist);
7602
}
7603

    
7604
function is_pseudo_interface($inf, $tap=true) {
7605
	global $config;
7606
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7607
	foreach ($psifs as $pif) {
7608
		if (substr($inf, 0, strlen($pif)) == $pif) {
7609
			if (($pif == 'ovpn') && $tap) {
7610
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7611
				$type = ($m[1] == 'c') ? 'client' : 'server';
7612
				foreach ($config['openvpn']['openvpn-'.$type] as $ovpn) {
7613
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7614
						return false;
7615
					} elseif ($ovpn['vpnid'] == $m[2]) {
7616
						return true;
7617
					}
7618
				}
7619
			} else {
7620
				return true;
7621
			}
7622
		}
7623
	}
7624
	return false;
7625
}
7626

    
7627
function is_stf_interface($inf) {
7628
	global $config;
7629

    
7630
	if (is_array($config['interfaces'][$inf]) &&
7631
	    (($config['interfaces'][$inf]['ipaddrv6'] == '6rd') ||
7632
	    ($config['interfaces'][$inf]['ipaddrv6'] == '6to4'))) {
7633
	    return true;
7634
	}
7635

    
7636
	return false;
7637
}
7638

    
7639
?>
(22-22/61)