Project

General

Profile

Download (221 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
require_once("wg.inc");
34

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

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

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

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

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

    
62
	return true;
63
}
64

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

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

    
76
	return $interface_arr_cache;
77
}
78

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

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

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

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

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

    
109

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

    
125
	$ifacedata = pfSense_getall_interface_addresses($realif);
126

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

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

    
139
	return false;
140
}
141

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

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

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

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

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

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

    
213
function vlan_valid_tag($tag = NULL) {
214

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

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

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

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

    
237
        return (false);
238
}
239

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

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

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

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

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

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

    
278
	return (NULL);
279
}
280

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

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

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

    
295
	return (false);
296
}
297

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

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

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

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

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

    
329
	return (NULL);
330
}
331

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

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

    
345
	$current_mac = get_interface_mac($interface);
346

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

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

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

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

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

    
416
	return (FALSE);
417
}
418

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

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

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

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

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

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

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

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

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

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

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

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

    
496
	interfaces_bring_up($vlanif);
497

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

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

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

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

    
518
	return $vlanif;
519
}
520

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
648
	return $vlanif;
649
}
650

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

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

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

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

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

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

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

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

    
706
	return $vlanif;
707
}
708

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

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

    
716
	$iflist = get_configured_interface_list();
717

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

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

    
745
}
746

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
854
	$checklist = get_configured_interface_list();
855

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

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

    
877
	interface_bridge_configure_advanced($bridge);
878

    
879
	interface_bridge_configure_ip6linklocal($bridge);
880

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1161
	interfaces_bring_up($laggif);
1162

    
1163
	return $laggif;
1164
}
1165

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

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

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

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

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

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

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

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

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

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

    
1240
	interfaces_bring_up($greif);
1241

    
1242
	return $greif;
1243
}
1244

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

    
1272
	if (!isset($config[$list][$entry]) || !is_array($config[$list][$entry])) {
1273
		return (NULL);
1274
	}
1275

    
1276
	foreach ($config[$list][$entry] as $ent) {
1277
		if ($ent[$entif] == $if) {
1278
			return ($ent);
1279
		}
1280
	}
1281
	return (NULL);
1282
}
1283

    
1284
function is_greipsec($if) {
1285
	global $config;
1286

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

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

    
1310
	if (!is_array($gif)) {
1311
		return -1;
1312
	}
1313

    
1314
	$realif = convert_friendly_interface_to_real_interface_name($gif['if']);
1315
	if (!interface_is_vlan($realif)) {
1316
		$realif = get_real_interface($gif['if']);
1317
	}
1318
	$ipaddr = get_interface_ip($gif['if']);
1319

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

    
1343
	if (platform_booting() || !(empty($gif['gifif']))) {
1344
		pfSense_interface_destroy($gif['gifif']);
1345
		pfSense_interface_create2($gif['gifif']);
1346
		$gifif = $gif['gifif'];
1347
	} else {
1348
		$gifif = pfSense_interface_create2("gif");
1349
	}
1350

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

    
1390
	if (!platform_booting()) {
1391
		$iflist = get_configured_interface_list();
1392
		foreach ($iflist as $ifname) {
1393
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1394
				if (get_interface_gateway($ifname)) {
1395
					system_routing_configure($ifname);
1396
					break;
1397
				}
1398
				if (get_interface_gateway_v6($ifname)) {
1399
					system_routing_configure($ifname);
1400
					break;
1401
				}
1402
			}
1403
		}
1404
	}
1405

    
1406

    
1407
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1408
		file_put_contents("{$g['tmp_path']}/{$gifif}_router",
1409
		    $gif['tunnel-remote-addr']);
1410
	} elseif (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1411
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6",
1412
		    $gif['tunnel-remote-addr']);
1413
	}
1414

    
1415
	route_add_or_change($gif['remote-addr'], $realifgw);
1416

    
1417
	if ($flush) {
1418
		get_interface_arr(true);
1419
	}
1420

    
1421
	interfaces_bring_up($gifif);
1422

    
1423
	return $gifif;
1424
}
1425

    
1426
/*
1427
 * $ipsecifnum = get_ipsecifnum($ikeid, $idx);
1428
 * locates and returns an ipsecifnum in the config.
1429
 */
1430
function get_ipsecifnum($ikeid, $idx) {
1431
	global $config;
1432

    
1433
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1434
	foreach ($config['ipsec']['vtimaps']['item'] as $vtimap) {
1435
		if (($vtimap['reqid'] == $ikeid) &&
1436
		    ($vtimap['index'] == $idx)) {
1437
			return $vtimap['ifnum'];
1438
		}
1439
	}
1440

    
1441
	return false;
1442
}
1443

    
1444
function ipsec_create_vtimap($ikeid, $idx) {
1445
	global $config;
1446

    
1447
	if ((($ikeid < 33) && ($idx < 10)) || (($ikeid < 10) && ($idx < 100))) {
1448
		$oldformat = "{$ikeid}00{$idx}";
1449
		return array(
1450
			"reqid" => $ikeid,
1451
			"index" => $idx,
1452
			"ifnum" => $oldformat
1453
		);
1454
	}
1455

    
1456
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1457

    
1458
	if (count($config['ipsec']['vtimaps']['item']) == 0) {
1459
		return array(
1460
			"reqid" => $ikeid,
1461
			"index" => $idx,
1462
			"ifnum" => 1
1463
		);
1464
	}
1465

    
1466
	$assigned = array_column($config['ipsec']['vtimaps']['item'], 'ifnum');
1467
	asort($assigned, SORT_NUMERIC);
1468
	$new = 1;
1469
	foreach($assigned as $ipsecifnum) {
1470
		if ($ipsecifnum != $new) {
1471
			return array(
1472
				"reqid" => $ikeid,
1473
				"index" => $idx,
1474
				"ifnum" => $new
1475
			);
1476
		}
1477
		if ($new <= 32767) {
1478
			$new++;
1479
		} else {
1480
			log_error(gettext("All 32767 ipsec interface numbers " .
1481
			    "have been assigned!"));
1482
			return(NULL);
1483
		}
1484
	}
1485
}
1486

    
1487
function ipsec_del_vtimap($phase2) {
1488
	global $config;
1489

    
1490
	init_config_arr(array('ipsec', 'vtimaps', 'item'));
1491

    
1492
	if (count($config['ipsec']['vtimaps']['item']) == 0) {
1493
		return;
1494
	}
1495

    
1496
	$a_vtimaps = &$config['ipsec']['vtimaps']['item'];
1497
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1498
	$last = '';
1499
	foreach ($a_vtimaps as $id => $vtimap) {
1500
		if ($vtimap['reqid'] == $phase1['ikeid']) {
1501
			$last = $id;
1502
		}
1503
	}
1504
	if (!is_numeric($last)) {
1505
		return false;
1506
	}
1507

    
1508
	$vtisubnet_spec = ipsec_vti($phase1, true);
1509
	if (($phase1['iketype'] == 'ikev1') || isset($phase1['splitconn']) ||
1510
	    (count($vtisubnet_spec) == 1)) {
1511
		unset($a_vtimaps[$last]);
1512
		return true;
1513
	}
1514
}
1515

    
1516
function interfaces_tunnel_configure($checkparent = 0, $realif = "", $type = "") {
1517
	global $config;
1518

    
1519
	if (!in_array($type, array('gre', 'gif'))) {
1520
		return;
1521
	}
1522

    
1523
	if (!is_array($config["{$type}s"][$type]) ||
1524
	    !count($config["{$type}s"][$type])) {
1525
		return;
1526
	}
1527

    
1528
	foreach ($config["{$type}s"][$type] as $i => $tunnel) {
1529
		if (empty($tunnel["{$type}if"])) {
1530
			$tunnel["{$type}if"] = $type . $i;
1531
		}
1532
		if (!empty($realif) && $realif != $tunnel["{$type}if"]) {
1533
			continue;
1534
		}
1535

    
1536
		if ($checkparent == 1) {
1537
			if (substr($tunnel['if'], 0, 4) == '_vip') {
1538
				continue;
1539
			}
1540
			if (substr($tunnel['if'], 0, 5) == '_lloc') {
1541
				continue;
1542
			}
1543
			if (!empty($config['interfaces'][$tunnel['if']]) &&
1544
			    $config['interfaces'][$tunnel['if']]['ipaddrv6'] ==
1545
			    "track6") {
1546
				continue;
1547
			}
1548
		} elseif ($checkparent == 2) {
1549
			if ((substr($tunnel['if'], 0, 4) != '_vip' &&
1550
			    substr($tunnel['if'], 0, 5) != '_lloc') &&
1551
			    (empty($config['interfaces'][$tunnel['if']]) ||
1552
			    $config['interfaces'][$tunnel['if']]['ipaddrv6'] !=
1553
			    "track6")) {
1554
				continue;
1555
			}
1556
		}
1557
		if ($type == 'gif') {
1558
			interface_gif_configure($tunnel, "", false);
1559
		} elseif ($type == 'gre') {
1560
			interface_gre_configure($tunnel, "", false);
1561
		}
1562
	}
1563

    
1564
	/* Invalidate cache */
1565
	get_interface_arr(true);
1566
}
1567

    
1568
/* Build a list of IPsec interfaces */
1569
function interface_ipsec_vti_list_p1($ph1ent) {
1570
	global $config;
1571
	$iface_list = array();
1572

    
1573
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1574
		return $iface_list;
1575
	}
1576

    
1577
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1578
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1579
		return $iface_list;
1580
	}
1581

    
1582
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1583
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1584
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1585
			$iface_list["ipsec".get_ipsecifnum($ph1ent['ikeid'], $idx)] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1586
		}
1587
	} else {
1588
		/* For IKEv2, only create one interface with additional addresses as aliases */
1589
		$iface_list["ipsec".get_ipsecifnum($ph1ent['ikeid'], 0)] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1590
	}
1591
	return $iface_list;
1592
}
1593
function interface_ipsec_vti_list_all() {
1594
	global $config;
1595
	$iface_list = array();
1596
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1597
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1598
			if ($ph1ent['disabled']) {
1599
				continue;
1600
			}
1601
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1602
		}
1603
	}
1604
	return $iface_list;
1605
}
1606

    
1607
function is_interface_ipsec_vti_assigned($phase2) {
1608
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1609
	$vti_interface = null;
1610
	$vtisubnet_spec = ipsec_vti($phase1, true);
1611
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1612
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1613
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1614
			foreach ($vtisubnet_spec as $idx => $vtisub) {
1615
				/* Is this for this P2? */
1616
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1617
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1618
					$vti_interface = "ipsec".get_ipsecifnum($phase1['ikeid'], $idx);
1619
				}
1620
			}
1621
		} else {
1622
			$vti_interface = "ipsec".get_ipsecifnum($phase1['ikeid'], 0);
1623
		}
1624
	}
1625
	/* Check if this interface is assigned */
1626
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1627
}
1628
function interface_ipsec_vti_configure($ph1ent) {
1629
	global $config;
1630

    
1631
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1632
		return false;
1633
	}
1634

    
1635
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1636
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1637
		return false;
1638
	}
1639

    
1640
	$left_spec = ipsec_get_phase1_src($ph1ent);
1641
	$right_spec = $ph1ent['remote-gateway'];
1642

    
1643
	$iface_addrs = array();
1644

    
1645
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1646
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1647
		/* Form a single interface for each P2 entry */
1648
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1649
			$ipsecifnum = get_ipsecifnum($ph1ent['ikeid'], $idx);
1650
			if (!is_array($iface_addrs[$ipsecifnum])) {
1651
				$iface_addrs[$ipsecifnum] = array();
1652
			}
1653
			$vtisub['alias'] = "";
1654
			$iface_addrs[$ipsecifnum][] = $vtisub;
1655
		}
1656
	} else {
1657
		/* For IKEv2, only create one interface with additional addresses as aliases */
1658
		$ipsecifnum = get_ipsecifnum($ph1ent['ikeid'], 0);
1659
		if (!is_array($iface_addrs[$ipsecifnum])) {
1660
			$iface_addrs[$ipsecifnum] = array();
1661
		}
1662
		$have_v4 = false;
1663
		$have_v6 = false;
1664
		foreach ($vtisubnet_spec as $vtisub) {
1665
			// Alias stuff
1666
			$vtisub['alias'] = "";
1667
			if (is_ipaddrv6($vtisub['left'])) {
1668
				if ($have_v6) {
1669
					$vtisub['alias'] = " alias";
1670
				}
1671
				$have_v6 = true;
1672
			} else {
1673
				if ($have_v4) {
1674
					$vtisub['alias'] = " alias";
1675
				}
1676
				$have_v4 = true;
1677
			}
1678
			$iface_addrs[$ipsecifnum][] = $vtisub;
1679
		}
1680
	}
1681

    
1682
	foreach ($iface_addrs as $ipsecifnum => $addrs) {
1683
		$ipsecif = "ipsec{$ipsecifnum}";
1684
		if (!is_array($addrs)) {
1685
			continue;
1686
		}
1687
		// Create IPsec interface
1688
		if (does_interface_exist($ipsecif)) {
1689
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy");
1690
		}
1691
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsecifnum));
1692

    
1693
		/* Apply the outer tunnel addresses to the interface */
1694
		$inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
1695
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} tunnel " . escapeshellarg($left_spec) . " " . escapeshellarg($right_spec) . " up");
1696

    
1697
		/* Loop through all of the addresses for this interface and apply them as needed */
1698
		foreach ($addrs as $addr) {
1699
			// apply interface addresses
1700
			if (is_v6($addr['left'])) {
1701
				$inet = "inet6";
1702
				$gwtype = "v6";
1703
				$right = '';
1704
			} else {
1705
				$inet = "inet";
1706
				$gwtype = "";
1707
				$right = escapeshellarg($addr['right']);
1708
			}
1709

    
1710
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . $right . $addr['alias']);
1711
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1712
			if (empty($addr['alias'])) {
1713
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1714
			}
1715
		}
1716
		/* Check/set the MTU if the user configured a custom value.
1717
		 * https://redmine.pfsense.org/issues/9111 */
1718
		$currentvtimtu = get_interface_mtu($ipsecif);
1719
		foreach ($config['interfaces'] as $tmpinterface) {
1720
			if ($tmpinterface['if'] == $ipsecif) {
1721
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1722
					$vtimtu = $tmpinterface['mtu'];
1723
				}
1724
			}
1725
		}
1726
		if (is_numericint($vtimtu)) {
1727
			if ($vtimtu != $currentvtimtu) {
1728
				mwexec("/sbin/ifconfig {$ipsecif} mtu {$vtimtu}");
1729
			}
1730
		}
1731
		system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1732
	}
1733
}
1734

    
1735
function interfaces_ipsec_vti_configure() {
1736
	global $config;
1737
	if (platform_booting()) {
1738
		echo gettext("Configuring IPsec VTI interfaces...");
1739
	}
1740
	if (is_array($config['ipsec']) &&
1741
	    is_array($config['ipsec']['phase1']) &&
1742
	    is_array($config['ipsec']['phase2'])) {
1743
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1744
			if ($ph1ent['disabled']) {
1745
				continue;
1746
			}
1747
			interface_ipsec_vti_configure($ph1ent);
1748
		}
1749
	}
1750
	if (platform_booting()) {
1751
		echo gettext("done.") . "\n";
1752
	}
1753
}
1754

    
1755
function interfaces_configure() {
1756
	global $config, $g;
1757

    
1758
	/* Set up our loopback interface */
1759
	interfaces_loopback_configure();
1760

    
1761
	/* create the unconfigured wireless clones */
1762
	interfaces_create_wireless_clones();
1763

    
1764
	/* set up LAGG virtual interfaces */
1765
	interfaces_lagg_configure();
1766

    
1767
	/* set up VLAN virtual interfaces */
1768
	interfaces_vlan_configure();
1769

    
1770
	interfaces_qinq_configure();
1771

    
1772
	$iflist = get_configured_interface_with_descr(true);
1773
	$delayed_list = array();
1774
	$bridge_list = array();
1775
	$track6_list = array();
1776
	$dhcp6c_list = array();
1777

    
1778
	/* This is needed to speedup interfaces on bootup. */
1779
	$reload = false;
1780
	if (!platform_booting()) {
1781
		$reload = true;
1782
	}
1783

    
1784
	foreach ($iflist as $if => $ifname) {
1785
		$realif = $config['interfaces'][$if]['if'];
1786
		if (!isset($config['interfaces'][$if]['enable'])) {
1787
			interface_bring_down($if, true);
1788
		} elseif (strstr($realif, "bridge")) {
1789
			$bridge_list[$if] = $ifname;
1790
		} elseif (strstr($realif, "gre")) {
1791
			$delayed_list[$if] = $ifname;
1792
		} elseif (strstr($realif, "gif")) {
1793
			$delayed_list[$if] = $ifname;
1794
		} elseif (strstr($realif, "ovpn")) {
1795
			continue;
1796
		} elseif (strstr($realif, "ipsec")) {
1797
			continue;
1798
		} elseif (!empty($config['interfaces'][$if]['ipaddrv6']) &&
1799
		    $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1800
			$track6_list[$if] = $ifname;
1801
		} else {
1802
			/* do not run dhcp6c if track interface does not exists
1803
			 * see https://redmine.pfsense.org/issues/3965
1804
			 * and https://redmine.pfsense.org/issues/11633 */ 
1805
			if (!empty($config['interfaces'][$if]['ipaddrv6']) &&
1806
			    $config['interfaces'][$if]['ipaddrv6'] == "dhcp6") {
1807
				$tr6list = link_interface_to_track6($if);
1808
				if (is_array($tr6list) && !empty($tr6list)) {
1809
					$dhcp6c_list[$if] = $ifname;
1810
					continue;
1811
				}
1812
			}
1813
			if (platform_booting()) {
1814
				printf(gettext("Configuring %s interface..."),
1815
				    $ifname);
1816
			}
1817

    
1818
			if ($g['debug']) {
1819
				log_error(sprintf(gettext("Configuring %s"),
1820
				    $ifname));
1821
			}
1822
			interface_configure($if, $reload);
1823
			if (platform_booting()) {
1824
				echo gettext("done.") . "\n";
1825
			}
1826
		}
1827
	}
1828

    
1829
	/*
1830
	 * NOTE: The following function parameter consists of
1831
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1832
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1833
	 */
1834

    
1835
	/* set up GRE virtual interfaces */
1836
	interfaces_tunnel_configure(1,'','gre');
1837

    
1838
	/* set up GIF virtual interfaces */
1839
	interfaces_tunnel_configure(1,'','gif');
1840

    
1841
	/* set up BRIDGE virtual interfaces */
1842
	interfaces_bridge_configure(1);
1843

    
1844
	foreach ($track6_list as $if => $ifname) {
1845
		if (platform_booting()) {
1846
			printf(gettext("Configuring %s interface..."), $ifname);
1847
		}
1848
		if ($g['debug']) {
1849
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1850
		}
1851

    
1852
		interface_configure($if, $reload);
1853

    
1854
		if (platform_booting()) {
1855
			echo gettext("done.") . "\n";
1856
		}
1857
	}
1858

    
1859
	/* bring up vip interfaces */
1860
	interfaces_vips_configure();
1861

    
1862
	/* set up GRE virtual interfaces */
1863
	interfaces_tunnel_configure(2,'','gre');
1864

    
1865
	/* set up GIF virtual interfaces */
1866
	interfaces_tunnel_configure(2,'','gif');
1867

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

    
1876
		interface_configure($if, $reload);
1877

    
1878
		if (platform_booting()) {
1879
			echo gettext("done.") . "\n";
1880
		}
1881
	}
1882

    
1883
	/* set up BRIDGE virtual interfaces */
1884
	interfaces_bridge_configure(2);
1885

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

    
1894
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1895
		// redmine #3997
1896
		interface_reconfigure($if, $reload);
1897
		interfaces_vips_configure($if);
1898

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

    
1904
	foreach ($dhcp6c_list as $if => $ifname) {
1905
		if (platform_booting()) {
1906
			printf(gettext("Configuring %s interface..."), $ifname);
1907
		}
1908
		if ($g['debug']) {
1909
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1910
		}
1911

    
1912
		interface_configure($if, $reload);
1913

    
1914
		if (platform_booting()) {
1915
			echo gettext("done.") . "\n";
1916
		}
1917
	}
1918

    
1919
	/* set up IPsec VTI interfaces */
1920
	interfaces_ipsec_vti_configure();
1921

    
1922
	/* configure interface groups */
1923
	interfaces_group_setup();
1924

    
1925
	if (!platform_booting()) {
1926
		/* reconfigure static routes (kernel may have deleted them) */
1927
		system_routing_configure();
1928

    
1929
		/* reload IPsec tunnels */
1930
		ipsec_configure();
1931

    
1932
		/* restart dns servers (defering dhcpd reload) */
1933
		if (isset($config['dnsmasq']['enable'])) {
1934
			services_dnsmasq_configure(false);
1935
		}
1936
		if (isset($config['unbound']['enable'])) {
1937
			services_unbound_configure(false);
1938
		}
1939

    
1940
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1941
		services_dhcpd_configure();
1942
	}
1943

    
1944
	return 0;
1945
}
1946

    
1947
function interface_reconfigure($interface = "wan", $reloadall = false) {
1948
	interface_bring_down($interface);
1949
	interface_configure($interface, $reloadall);
1950
}
1951

    
1952
function interface_vip_bring_down($vip) {
1953
	global $g;
1954

    
1955
	$vipif = get_real_interface($vip['interface']);
1956
	switch ($vip['mode']) {
1957
		case "proxyarp":
1958
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1959
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1960
			}
1961
			break;
1962
		case "ipalias":
1963
			if (does_interface_exist($vipif)) {
1964
				if (is_ipaddrv6($vip['subnet'])) {
1965
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1966
				} else {
1967
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1968
				}
1969
			}
1970
			break;
1971
		case "carp":
1972
			/* XXX: Is enough to delete ip address? */
1973
			if (does_interface_exist($vipif)) {
1974
				if (is_ipaddrv6($vip['subnet'])) {
1975
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1976
				} else {
1977
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1978
				}
1979
			}
1980
			break;
1981
	}
1982
}
1983

    
1984
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1985
	global $config, $g;
1986

    
1987
	if (!isset($config['interfaces'][$interface])) {
1988
		return;
1989
	}
1990

    
1991
	if (substr($config['interfaces'][$interface]['if'], 0, 2) == 'wg') {
1992
		require_once('wg.inc');
1993
		if ($destroy) {
1994
			wg_destroy_if($config['interfaces'][$interface]['if']);
1995
		}
1996
		return;
1997
	}
1998

    
1999
	if ($g['debug']) {
2000
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
2001
	}
2002

    
2003
	/*
2004
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
2005
	 * In this case the real $realif of v4 is different from that of v6 for operation.
2006
	 * Keep this in mind while doing changes here!
2007
	 */
2008
	if ($ifacecfg === false) {
2009
		$ifcfg = $config['interfaces'][$interface];
2010
		$ppps = $config['ppps']['ppp'];
2011
		$realif = get_real_interface($interface);
2012
		$realifv6 = get_real_interface($interface, "inet6", true);
2013
	} elseif (!is_array($ifacecfg)) {
2014
		log_error(gettext("Wrong parameters used during interface_bring_down"));
2015
		$ifcfg = $config['interfaces'][$interface];
2016
		$ppps = $config['ppps']['ppp'];
2017
		$realif = get_real_interface($interface);
2018
		$realifv6 = get_real_interface($interface, "inet6", true);
2019
	} else {
2020
		$ifcfg = $ifacecfg['ifcfg'];
2021
		$ppps = $ifacecfg['ppps'];
2022
		if (isset($ifacecfg['ifcfg']['realif'])) {
2023
			$realif = $ifacecfg['ifcfg']['realif'];
2024
			/* XXX: Any better way? */
2025
			$realifv6 = $realif;
2026
		} else {
2027
			$realif = get_real_interface($interface);
2028
			$realifv6 = get_real_interface($interface, "inet6", true);
2029
		}
2030
	}
2031

    
2032
	switch ($ifcfg['ipaddr']) {
2033
		case "ppp":
2034
		case "pppoe":
2035
		case "pptp":
2036
		case "l2tp":
2037
			if (is_array($ppps) && count($ppps)) {
2038
				foreach ($ppps as $pppid => $ppp) {
2039
					if ($realif == $ppp['if']) {
2040
						if (isset($ppp['ondemand']) && !$destroy) {
2041
							send_event("interface reconfigure {$interface}");
2042
							break;
2043
						}
2044
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
2045
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
2046
							sleep(2);
2047
						}
2048
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
2049
						break;
2050
					}
2051
				}
2052
			}
2053
			break;
2054
		case "dhcp":
2055
			kill_dhclient_process($realif);
2056
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
2057
			if (does_interface_exist("$realif")) {
2058
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
2059
				interface_vip_cleanup($interface, "inet4");
2060
				if ($destroy == true) {
2061
					pfSense_interface_flags($realif, -IFF_UP);
2062
				}
2063
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2064
			}
2065
			break;
2066
		default:
2067
			if (does_interface_exist("$realif")) {
2068
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
2069
				interface_vip_cleanup($interface, "inet4");
2070
				if ($destroy == true) {
2071
					pfSense_interface_flags($realif, -IFF_UP);
2072
				}
2073
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2074
			}
2075
			break;
2076
	}
2077

    
2078
	$track6 = array();
2079
	switch ($ifcfg['ipaddrv6']) {
2080
		case "slaac":
2081
		case "dhcp6":
2082
			kill_dhcp6client_process($realif, $destroy, false);
2083
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}.conf");
2084
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
2085
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh");
2086
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$realifv6}_script.sh");
2087
			if (does_interface_exist($realifv6)) {
2088
				mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 -accept_rtadv");
2089
				$ip6 = find_interface_ipv6($realifv6);
2090
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
2091
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
2092
				}
2093
				interface_vip_cleanup($interface, "inet6");
2094
				if ($destroy == true) {
2095
					pfSense_interface_flags($realif, -IFF_UP);
2096
				}
2097
			}
2098
			$track6 = link_interface_to_track6($interface);
2099
			break;
2100
		case "6rd":
2101
		case "6to4":
2102
			$realif = "{$interface}_stf";
2103
			if (does_interface_exist("$realif")) {
2104
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
2105
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
2106
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
2107
					$destroy = true;
2108
				} else {
2109
					/* get_interface_ipv6() returns empty value if interface is being disabled */
2110
					$ip6 = get_interface_ipv6($interface);
2111
					if (is_ipaddrv6($ip6)) {
2112
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2113
					}
2114
				}
2115
				interface_vip_cleanup($interface, "inet6");
2116
				if ($destroy == true) {
2117
					pfSense_interface_flags($realif, -IFF_UP);
2118
				}
2119
			}
2120
			$track6 = link_interface_to_track6($interface);
2121
			break;
2122
		default:
2123
			if (does_interface_exist("$realif")) {
2124
				$ip6 = get_interface_ipv6($interface);
2125
				if (is_ipaddrv6($ip6)) {
2126
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2127
				}
2128
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
2129
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
2130
				}
2131
				interface_vip_cleanup($interface, "inet6");
2132
				if ($destroy == true) {
2133
					pfSense_interface_flags($realif, -IFF_UP);
2134
				}
2135
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2136
			}
2137
			$track6 = link_interface_to_track6($interface);
2138
			break;
2139
	}
2140

    
2141
	if (!empty($track6) && is_array($track6)) {
2142
		if (!function_exists('services_dhcpd_configure')) {
2143
			require_once('services.inc');
2144
		}
2145
		/* Bring down radvd and dhcp6 on these interfaces */
2146
		services_dhcpd_configure('inet6', $track6);
2147
	}
2148

    
2149
	$old_router = '';
2150
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
2151
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
2152
	}
2153

    
2154
	/* remove interface up file if it exists */
2155
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
2156
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
2157
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
2158
	unlink_if_exists("{$g['tmp_path']}/{$realif}_router");
2159
	unlink_if_exists("{$g['tmp_path']}/{$realif}_routerv6");
2160
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
2161
	unlink_if_exists("{$g['varetc_path']}/nameserver_v6{$interface}");
2162
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
2163
	unlink_if_exists("{$g['varetc_path']}/searchdomain_v6{$interface}");
2164

    
2165
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
2166
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
2167
	if (is_array($ifcfg['wireless'])) {
2168
		kill_hostapd($realif);
2169
		mwexec(kill_wpasupplicant($realif));
2170
		unlink_if_exists("{$g['varetc_path']}/wpa_supplicant_{$realif}.*");
2171
		unlink_if_exists("{$g['varetc_path']}/hostapd_{$realif}.conf");
2172
	}
2173

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

    
2178
			/* Invalidate cache */
2179
			get_interface_arr(true);
2180
		}
2181
	}
2182

    
2183
	return;
2184
}
2185

    
2186
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
2187
	global $config;
2188
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
2189
		unset($config["virtualip_carp_maintenancemode"]);
2190
		write_config("Leave CARP maintenance mode");
2191
	} elseif (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
2192
		$config["virtualip_carp_maintenancemode"] = true;
2193
		write_config(gettext("Enter CARP maintenance mode"));
2194
	}
2195
	init_config_arr(array('virtualip', 'vip'));
2196
	$viparr = &$config['virtualip']['vip'];
2197

    
2198
	if (is_array($viparr)) {
2199
		foreach ($viparr as $vip) {
2200
			if ($vip['mode'] == "carp") {
2201
				interface_carp_configure($vip, true);
2202
			}
2203
		}
2204
	}
2205
}
2206

    
2207
function interface_wait_tentative($interface, $timeout = 10) {
2208
	if (!does_interface_exist($interface)) {
2209
		return false;
2210
	}
2211

    
2212
	$time = 0;
2213
	while ($time <= $timeout) {
2214
		$if = pfSense_get_interface_addresses($interface);
2215
		if (!isset($if['tentative'])) {
2216
			return true;
2217
		}
2218
		sleep(1);
2219
		$time++;
2220
	}
2221

    
2222
	return false;
2223
}
2224

    
2225
function interface_isppp_type($interface) {
2226
	global $config;
2227

    
2228
	if (!is_array($config['interfaces'][$interface])) {
2229
		return false;
2230
	}
2231

    
2232
	switch ($config['interfaces'][$interface]['ipaddr']) {
2233
		case 'pptp':
2234
		case 'l2tp':
2235
		case 'pppoe':
2236
		case 'ppp':
2237
			return true;
2238
			break;
2239
		default:
2240
			return false;
2241
			break;
2242
	}
2243
}
2244

    
2245
function interfaces_ptpid_used($ptpid) {
2246
	global $config;
2247

    
2248
	if (is_array($config['ppps']['ppp'])) {
2249
		foreach ($config['ppps']['ppp'] as & $settings) {
2250
			if ($ptpid == $settings['ptpid']) {
2251
				return true;
2252
			}
2253
		}
2254
	}
2255

    
2256
	return false;
2257
}
2258

    
2259
function interfaces_ptpid_next() {
2260

    
2261
	$ptpid = 0;
2262
	while (interfaces_ptpid_used($ptpid)) {
2263
		$ptpid++;
2264
	}
2265

    
2266
	return $ptpid;
2267
}
2268

    
2269
function getMPDCRONSettings($pppif) {
2270
	global $config;
2271

    
2272
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2273
	if (is_array($config['cron']['item'])) {
2274
		foreach ($config['cron']['item'] as $i => $item) {
2275
			if (stripos($item['command'], $cron_cmd_file) !== false) {
2276
				return array("ID" => $i, "ITEM" => $item);
2277
			}
2278
		}
2279
	}
2280

    
2281
	return NULL;
2282
}
2283

    
2284
function handle_pppoe_reset($post_array) {
2285
	global $config, $g;
2286

    
2287
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2288
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2289

    
2290
	if (!is_array($config['cron']['item'])) {
2291
		$config['cron']['item'] = array();
2292
	}
2293

    
2294
	$itemhash = getMPDCRONSettings($pppif);
2295

    
2296
	// reset cron items if necessary and return
2297
	if (empty($post_array['pppoe-reset-type'])) {
2298
		if (isset($itemhash)) {
2299
			unset($config['cron']['item'][$itemhash['ID']]);
2300
		}
2301
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2302
		return;
2303
	}
2304

    
2305
	if (empty($itemhash)) {
2306
		$itemhash = array();
2307
	}
2308
	$item = array();
2309
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
2310
		$item['minute'] = $post_array['pppoe_resetminute'];
2311
		$item['hour'] = $post_array['pppoe_resethour'];
2312
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
2313
			$date = explode("/", $post_array['pppoe_resetdate']);
2314
			$item['mday'] = $date[1];
2315
			$item['month'] = $date[0];
2316
		} else {
2317
			$item['mday'] = "*";
2318
			$item['month'] = "*";
2319
		}
2320
		$item['wday'] = "*";
2321
		$item['who'] = "root";
2322
		$item['command'] = $cron_cmd_file;
2323
	} elseif (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
2324
		switch ($post_array['pppoe_pr_preset_val']) {
2325
			case "monthly":
2326
				$item['minute'] = "0";
2327
				$item['hour'] = "0";
2328
				$item['mday'] = "1";
2329
				$item['month'] = "*";
2330
				$item['wday'] = "*";
2331
				break;
2332
			case "weekly":
2333
				$item['minute'] = "0";
2334
				$item['hour'] = "0";
2335
				$item['mday'] = "*";
2336
				$item['month'] = "*";
2337
				$item['wday'] = "0";
2338
				break;
2339
			case "daily":
2340
				$item['minute'] = "0";
2341
				$item['hour'] = "0";
2342
				$item['mday'] = "*";
2343
				$item['month'] = "*";
2344
				$item['wday'] = "*";
2345
				break;
2346
			case "hourly":
2347
				$item['minute'] = "0";
2348
				$item['hour'] = "*";
2349
				$item['mday'] = "*";
2350
				$item['month'] = "*";
2351
				$item['wday'] = "*";
2352
				break;
2353
		} // end switch
2354
		$item['who'] = "root";
2355
		$item['command'] = $cron_cmd_file;
2356
	}
2357
	if (empty($item)) {
2358
		return;
2359
	}
2360
	if (isset($itemhash['ID'])) {
2361
		$config['cron']['item'][$itemhash['ID']] = $item;
2362
	} else {
2363
		$config['cron']['item'][] = $item;
2364
	}
2365
}
2366

    
2367
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2368
	global $config;
2369
	$ppp_list = array();
2370
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2371
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2372
			$ports = explode(",", $ppp['ports']);
2373
			foreach($ports as $port) {
2374
				foreach($triggerinterfaces as $vip) {
2375
					if ($port == "_vip{$vip['uniqid']}") {
2376
						$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2377
						$ppp_list[$if] = 1;
2378
					}
2379
				}
2380
			}
2381
		}
2382
	}
2383
	foreach($ppp_list as $pppif => $dummy) {
2384
		interface_ppps_configure($pppif);
2385
	}
2386
}
2387

    
2388
/*
2389
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2390
 * It writes the mpd config file to /var/etc every time the link is opened.
2391
 */
2392
function interface_ppps_configure($interface) {
2393
	global $config, $g;
2394

    
2395
	/* Return for unassigned interfaces. This is a minimum requirement. */
2396
	if (empty($config['interfaces'][$interface])) {
2397
		return 0;
2398
	}
2399
	$ifcfg = $config['interfaces'][$interface];
2400
	if (!isset($ifcfg['enable'])) {
2401
		return 0;
2402
	}
2403

    
2404
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2405
	if (!is_dir("/var/spool/lock")) {
2406
		mkdir("/var/spool/lock", 0777, true);
2407
	}
2408
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2409
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2410
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2411
	}
2412

    
2413
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2414
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2415
			if ($ifcfg['if'] == $ppp['if']) {
2416
				break;
2417
			}
2418
		}
2419
	}
2420
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2421
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2422
		return 0;
2423
	}
2424
	$pppif = $ifcfg['if'];
2425
	if ($ppp['type'] == "ppp") {
2426
		$type = "modem";
2427
	} else {
2428
		$type = $ppp['type'];
2429
	}
2430
	$upper_type = strtoupper($ppp['type']);
2431

    
2432
	$confports = explode(',', $ppp['ports']);
2433
	if ($type == "modem") {
2434
		$ports = $confports;
2435
	} else {
2436
		$ports = array();
2437
		foreach ($confports as $pid => $port) {
2438
			if (strstr($port, "_vip")) {
2439
				if (get_carp_interface_status($port) != "MASTER") {
2440
					continue;
2441
				}
2442
			}
2443
			$ports[$pid] = get_real_interface($port);
2444
			if (empty($ports[$pid])) {
2445
				return 0;
2446
			}
2447
		}
2448
	}
2449
	$localips = explode(',', $ppp['localip']);
2450
	$gateways = explode(',', $ppp['gateway']);
2451
	$subnets = explode(',', $ppp['subnet']);
2452

    
2453
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2454
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2455
	 */
2456
	foreach ($ports as $pid => $port) {
2457
		switch ($ppp['type']) {
2458
			case "pppoe":
2459
				/* Bring the parent interface up */
2460
				interfaces_bring_up($port);
2461
				pfSense_ngctl_attach(".", $port);
2462
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2463
				$ngif = str_replace(".", "_", $port);
2464
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2465
				break;
2466
			case "pptp":
2467
			case "l2tp":
2468
				/* configure interface */
2469
				if (is_ipaddr($localips[$pid])) {
2470
					// Manually configure interface IP/subnet
2471
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2472
					interfaces_bring_up($port);
2473
				} elseif (empty($localips[$pid])) {
2474
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2475
				}
2476

    
2477
				if (!is_ipaddr($localips[$pid])) {
2478
					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));
2479
					$localips[$pid] = "0.0.0.0";
2480
				}
2481
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2482
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2483
				}
2484
				if (!is_ipaddr($gateways[$pid])) {
2485
					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));
2486
					return 0;
2487
				}
2488
				pfSense_ngctl_attach(".", $port);
2489
				break;
2490
			case "ppp":
2491
				if (!file_exists("{$port}")) {
2492
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2493
					return 0;
2494
				}
2495
				break;
2496
			default:
2497
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2498
				break;
2499
		}
2500
	}
2501

    
2502
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2503
	    (is_array($ports) && count($ports) > 1)) {
2504
		$multilink = "enable";
2505
	} else {
2506
		$multilink = "disable";
2507
	}
2508

    
2509
	if ($type == "modem") {
2510
		if (is_ipaddr($ppp['localip'])) {
2511
			$localip = $ppp['localip'];
2512
		} else {
2513
			$localip = '0.0.0.0';
2514
		}
2515

    
2516
		if (is_ipaddr($ppp['gateway'])) {
2517
			$gateway = $ppp['gateway'];
2518
		} else {
2519
			$gateway = "10.64.64.{$pppid}";
2520
		}
2521
		$ranges = "{$localip}/0 {$gateway}/0";
2522

    
2523
		if (empty($ppp['apnum'])) {
2524
			$ppp['apnum'] = 1;
2525
		}
2526
	} else {
2527
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2528
	}
2529

    
2530
	if (isset($ppp['ondemand'])) {
2531
		$ondemand = "enable";
2532
	} else {
2533
		$ondemand = "disable";
2534
	}
2535
	if (!isset($ppp['idletimeout'])) {
2536
		$ppp['idletimeout'] = 0;
2537
	}
2538

    
2539
	if (empty($ppp['username']) && $type == "modem") {
2540
		$ppp['username'] = "user";
2541
		$ppp['password'] = "none";
2542
	}
2543
	if (empty($ppp['password']) && $type == "modem") {
2544
		$passwd = "none";
2545
	} else {
2546
		$passwd = base64_decode($ppp['password']);
2547
	}
2548

    
2549
	$bandwidths = explode(',', $ppp['bandwidth']);
2550
	$defaultmtu = "1492";
2551
	if (!empty($ifcfg['mtu'])) {
2552
		$defaultmtu = intval($ifcfg['mtu']);
2553
	}
2554
	if (isset($ppp['mtu'])) {
2555
		$mtus = explode(',', $ppp['mtu']);
2556
	}
2557
	if (isset($ppp['mru'])) {
2558
		$mrus = explode(',', $ppp['mru']);
2559
	}
2560
	if (isset($ppp['mrru'])) {
2561
		$mrrus = explode(',', $ppp['mrru']);
2562
	}
2563
	if (!empty($ifcfg['ipaddrv6'])) {
2564
		$ipv6cp = "set bundle enable ipv6cp";
2565
	}
2566

    
2567
	// Construct the mpd.conf file
2568
	$mpdconf = <<<EOD
2569
startup:
2570
	# configure the console
2571
	set console close
2572
	# configure the web server
2573
	set web close
2574

    
2575
default:
2576
{$ppp['type']}client:
2577
	create bundle static {$interface}
2578
	{$ipv6cp}
2579
	set iface name {$pppif}
2580

    
2581
EOD;
2582
	$setdefaultgw = false;
2583
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2584
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2585
	if ($defgw4['interface'] == $interface) {
2586
		$setdefaultgw = true;
2587
	}
2588

    
2589
/* Omit this, we maintain the default route by other means, and it causes problems with
2590
 * default gateway switching. See redmine #1837 for original issue
2591
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2592
 * edge case. redmine #6495 open to address.
2593
 */
2594
	if ($setdefaultgw == true) {
2595
		$mpdconf .= <<<EOD
2596
	set iface route default
2597

    
2598
EOD;
2599
	}
2600

    
2601
	$mpdconf .= <<<EOD
2602
	set iface {$ondemand} on-demand
2603
	set iface idle {$ppp['idletimeout']}
2604

    
2605
EOD;
2606

    
2607
	if (isset($ppp['ondemand'])) {
2608
		$mpdconf .= <<<EOD
2609
	set iface addrs 10.10.1.1 10.10.1.2
2610

    
2611
EOD;
2612
	}
2613

    
2614
	if (isset($ppp['mtu-override']) &&
2615
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2616
		/* Find the smaller MTU set on ports */
2617
		$mtu = $defaultmtu;
2618
		foreach ($ports as $pid => $port) {
2619
			if (empty($mtus[$pid])) {
2620
				$mtus[$pid] = $defaultmtu;
2621
			}
2622
			if ($type == "pppoe") {
2623
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2624
					$mtus[$pid] = get_interface_mtu($port) - 8;
2625
				}
2626
			}
2627
			if ($mtu > $mtus[$pid]) {
2628
				$mtu = $mtus[$pid];
2629
			}
2630
		}
2631
		$mpdconf .= <<<EOD
2632
	set iface mtu {$mtu} override
2633

    
2634
EOD;
2635
	}
2636

    
2637
	if (isset($ppp['tcpmssfix'])) {
2638
		$tcpmss = "disable";
2639
	} else {
2640
		$tcpmss = "enable";
2641
	}
2642
	$mpdconf .= <<<EOD
2643
	set iface {$tcpmss} tcpmssfix
2644

    
2645
EOD;
2646

    
2647
	$mpdconf .= <<<EOD
2648
	set iface up-script /usr/local/sbin/ppp-linkup
2649
	set iface down-script /usr/local/sbin/ppp-linkdown
2650
	set ipcp ranges {$ranges}
2651

    
2652
EOD;
2653
	if (isset($ppp['vjcomp'])) {
2654
		$mpdconf .= <<<EOD
2655
	set ipcp no vjcomp
2656

    
2657
EOD;
2658
	}
2659

    
2660
	if (isset($config['system']['dnsallowoverride'])) {
2661
		$mpdconf .= <<<EOD
2662
	set ipcp enable req-pri-dns
2663
	set ipcp enable req-sec-dns
2664

    
2665
EOD;
2666
	}
2667

    
2668
	if (!isset($ppp['verbose_log'])) {
2669
		$mpdconf .= <<<EOD
2670
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2671

    
2672
EOD;
2673
	}
2674

    
2675
	foreach ($ports as $pid => $port) {
2676
		$port = get_real_interface($port);
2677
		$mpdconf .= <<<EOD
2678

    
2679
	create link static {$interface}_link{$pid} {$type}
2680
	set link action bundle {$interface}
2681
	set link {$multilink} multilink
2682
	set link keep-alive 10 60
2683
	set link max-redial 0
2684

    
2685
EOD;
2686
		if (isset($ppp['shortseq'])) {
2687
			$mpdconf .= <<<EOD
2688
	set link no shortseq
2689

    
2690
EOD;
2691
		}
2692

    
2693
		if (isset($ppp['acfcomp'])) {
2694
			$mpdconf .= <<<EOD
2695
	set link no acfcomp
2696

    
2697
EOD;
2698
		}
2699

    
2700
		if (isset($ppp['protocomp'])) {
2701
			$mpdconf .= <<<EOD
2702
	set link no protocomp
2703

    
2704
EOD;
2705
		}
2706

    
2707
		$mpdconf .= <<<EOD
2708
	set link disable chap pap
2709
	set link accept chap pap eap
2710
	set link disable incoming
2711

    
2712
EOD;
2713

    
2714

    
2715
		if (!empty($bandwidths[$pid])) {
2716
			$mpdconf .= <<<EOD
2717
	set link bandwidth {$bandwidths[$pid]}
2718

    
2719
EOD;
2720
		}
2721

    
2722
		if (empty($mtus[$pid])) {
2723
			$mtus[$pid] = $defaultmtu;
2724
		}
2725
		if ($type == "pppoe") {
2726
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2727
				$mtus[$pid] = get_interface_mtu($port) - 8;
2728
			}
2729
		}
2730
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2731
		    !isset($ppp['mtu-override']) &&
2732
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2733
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2734
			$mpdconf .= <<<EOD
2735
	set link mtu {$mtus[$pid]}
2736

    
2737
EOD;
2738
		}
2739

    
2740
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2741
		    !isset($ppp['mtu-override']) &&
2742
		    !empty($mrus[$pid])) {
2743
			$mpdconf .= <<<EOD
2744
	set link mru {$mrus[$pid]}
2745

    
2746
EOD;
2747
		}
2748

    
2749
		if (!empty($mrrus[$pid])) {
2750
			$mpdconf .= <<<EOD
2751
	set link mrru {$mrrus[$pid]}
2752

    
2753
EOD;
2754
		}
2755

    
2756
		$mpdconf .= <<<EOD
2757
	set auth authname "{$ppp['username']}"
2758
	set auth password {$passwd}
2759

    
2760
EOD;
2761
		if ($type == "modem") {
2762
			$mpdconf .= <<<EOD
2763
	set modem device {$ppp['ports']}
2764
	set modem script DialPeer
2765
	set modem idle-script Ringback
2766
	set modem watch -cd
2767
	set modem var \$DialPrefix "DT"
2768
	set modem var \$Telephone "{$ppp['phone']}"
2769

    
2770
EOD;
2771
		}
2772
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2773
			$mpdconf .= <<<EOD
2774
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2775

    
2776
EOD;
2777
		}
2778
		if (isset($ppp['initstr']) && $type == "modem") {
2779
			$initstr = base64_decode($ppp['initstr']);
2780
			$mpdconf .= <<<EOD
2781
	set modem var \$InitString "{$initstr}"
2782

    
2783
EOD;
2784
		}
2785
		if (isset($ppp['simpin']) && $type == "modem") {
2786
			if ($ppp['pin-wait'] == "") {
2787
				$ppp['pin-wait'] = 0;
2788
			}
2789
			$mpdconf .= <<<EOD
2790
	set modem var \$SimPin "{$ppp['simpin']}"
2791
	set modem var \$PinWait "{$ppp['pin-wait']}"
2792

    
2793
EOD;
2794
		}
2795
		if (isset($ppp['apn']) && $type == "modem") {
2796
			$mpdconf .= <<<EOD
2797
	set modem var \$APN "{$ppp['apn']}"
2798
	set modem var \$APNum "{$ppp['apnum']}"
2799

    
2800
EOD;
2801
		}
2802
		if ($type == "pppoe") {
2803
			$hostuniq = '';
2804
			if (!empty($ppp['hostuniq'])) {
2805
				if (preg_match('/^0x[a-fA-F0-9]+$/', $ppp['hostuniq'])) {
2806
					$hostuniq = strtolower($ppp['hostuniq']) .'|';
2807
				} elseif (preg_match('/^[a-zA-Z0-9]+$/i', $ppp['hostuniq'])) {
2808
					$hostuniq = '0x' . bin2hex($ppp['hostuniq']) . '|';
2809
				}
2810
			}
2811
			// Send a null service name if none is set.
2812
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2813
			$mpdconf .= <<<EOD
2814
	set pppoe service "{$hostuniq}{$provider}"
2815

    
2816
EOD;
2817
		}
2818
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2819
			$mpdconf .= <<<EOD
2820
	set pppoe max-payload {$mtus[$pid]}
2821

    
2822
EOD;
2823
		}
2824
		if ($type == "pppoe") {
2825
			$mpdconf .= <<<EOD
2826
	set pppoe iface {$port}
2827

    
2828
EOD;
2829
		}
2830

    
2831
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2832
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2833
			$mpdconf .= <<<EOD
2834
	set l2tp secret "{$secret}"
2835

    
2836
EOD;
2837
		}
2838

    
2839
		if (($type == "pptp") || ($type == "l2tp")) {
2840
			$mpdconf .= <<<EOD
2841
	set {$type} self {$localips[$pid]}
2842
	set {$type} peer {$gateways[$pid]}
2843

    
2844
EOD;
2845
		}
2846

    
2847
		$mpdconf .= "\topen\n";
2848
	} //end foreach ($port)
2849

    
2850

    
2851
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2852
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2853
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2854
	} else {
2855
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2856
		if (!$fd) {
2857
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2858
			return 0;
2859
		}
2860
		// Write out mpd_ppp.conf
2861
		fwrite($fd, $mpdconf);
2862
		fclose($fd);
2863
		unset($mpdconf);
2864
	}
2865

    
2866
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2867
	if (isset($ppp['uptime'])) {
2868
		if (!file_exists("/conf/{$pppif}.log")) {
2869
			file_put_contents("/conf/{$pppif}.log", '');
2870
		}
2871
	} else {
2872
		if (file_exists("/conf/{$pppif}.log")) {
2873
			@unlink("/conf/{$pppif}.log");
2874
		}
2875
	}
2876

    
2877
	/* clean up old lock files */
2878
	foreach ($ports as $port) {
2879
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2880
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2881
		}
2882
	}
2883

    
2884
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2885
	/* random IPv6 interface identifier during boot. More details at */
2886
	/* https://forum.netgate.com/post/592474 */
2887
	if (platform_booting() && is_array($config['interfaces'])) {
2888
		$count = 0;
2889
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2890
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2891
				$tempaddr[$count]['if'] = $tempiface['if'];
2892
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2893
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2894
				$count++;
2895
			}
2896
			// Maximum /31 is is x.y.z.254/31
2897
			if ($count > 122) {
2898
				break;
2899
			}
2900
		}
2901
		unset($count);
2902
	}
2903

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

    
2909
	// Check for PPPoE periodic reset request
2910
	if ($type == "pppoe") {
2911
		if (!empty($ppp['pppoe-reset-type'])) {
2912
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2913
		} else {
2914
			interface_setup_pppoe_reset_file($ppp['if']);
2915
		}
2916
	}
2917
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2918
	$i = 0;
2919
	while ($i < 10) {
2920
		if (does_interface_exist($ppp['if'], true)) {
2921
			break;
2922
		}
2923
		sleep(3);
2924
		$i++;
2925
	}
2926

    
2927
	/* Remove all temporary bogon IPv4 addresses */
2928
	if (is_array($tempaddr)) {
2929
		foreach ($tempaddr as $tempiface) {
2930
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2931
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2932
			}
2933
		}
2934
		unset ($tempaddr);
2935
	}
2936

    
2937
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2938
	/* We should be able to launch the right version for each modem */
2939
	/* We can also guess the mondev from the manufacturer */
2940
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2941
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2942
	foreach ($ports as $port) {
2943
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2944
			$mondev = substr(basename($port), 0, -1);
2945
			$devlist = glob("/dev/{$mondev}?");
2946
			$mondev = basename(end($devlist));
2947
		}
2948
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2949
			$mondev = substr(basename($port), 0, -1) . "1";
2950
		}
2951
		if ($mondev != '') {
2952
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2953
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2954
		}
2955
	}
2956

    
2957
	return 1;
2958
}
2959

    
2960
function interfaces_sync_setup() {
2961
	global $g, $config;
2962

    
2963
	if (isset($config['system']['developerspew'])) {
2964
		$mt = microtime();
2965
		echo "interfaces_sync_setup() being called $mt\n";
2966
	}
2967

    
2968
	if (platform_booting()) {
2969
		echo gettext("Configuring CARP settings...");
2970
		mute_kernel_msgs();
2971
	}
2972

    
2973
	/* suck in configuration items */
2974
	if ($config['hasync']) {
2975
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2976
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2977
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2978
	}
2979

    
2980
	set_sysctl(array(
2981
		"net.inet.carp.preempt" => "1",
2982
		"net.inet.carp.log" => "1")
2983
	);
2984

    
2985
	if (!empty($pfsyncinterface)) {
2986
		$carp_sync_int = get_real_interface($pfsyncinterface);
2987
	}
2988

    
2989
	/* setup pfsync interface */
2990
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2991
		if (is_ipaddr($pfsyncpeerip)) {
2992
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2993
		} else {
2994
			$syncpeer = "-syncpeer";
2995
		}
2996

    
2997
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} " .
2998
		    "{$syncpeer} up");
2999
		mwexec("/sbin/ifconfig pfsync0 -defer");
3000

    
3001
		/*
3002
		 * XXX: Handle an issue with pfsync(4) and carp(4). In a
3003
		 * cluster carp will come up before pfsync(4) has updated and
3004
		 * so will cause issues for existing sessions.
3005
		 */
3006
		log_error(gettext("waiting for pfsync..."));
3007

    
3008
		$i = 0;
3009
		do {
3010
			sleep(1);
3011
			$_gb = exec('/sbin/ifconfig pfsync0 | ' .
3012
			    '/usr/bin/grep -q "syncok: 0" 2>/dev/null', $output,
3013
			    $rc);
3014
			$i++;
3015
		} while ($rc != 0 && $i <= 30);
3016

    
3017
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
3018
		log_error(gettext("Configuring CARP settings finalize..."));
3019
	} else {
3020
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down");
3021
	}
3022

    
3023
	$carplist = get_configured_vip_list('all', VIP_CARP);
3024
	if (is_array($carplist) && count($carplist) > 0) {
3025
		set_single_sysctl("net.inet.carp.allow", "1");
3026
	} else {
3027
		set_single_sysctl("net.inet.carp.allow", "0");
3028
	}
3029

    
3030
	if (platform_booting()) {
3031
		unmute_kernel_msgs();
3032
		echo gettext("done.") . "\n";
3033
	}
3034
}
3035

    
3036
function interface_proxyarp_configure($interface = "") {
3037
	global $config, $g;
3038
	if (isset($config['system']['developerspew'])) {
3039
		$mt = microtime();
3040
		echo "interface_proxyarp_configure() being called $mt\n";
3041
	}
3042

    
3043
	/* kill any running choparp */
3044
	if (empty($interface)) {
3045
		killbyname("choparp");
3046
	} else {
3047
		$vipif = get_real_interface($interface);
3048
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
3049
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
3050
		}
3051
	}
3052

    
3053
	$paa = array();
3054
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
3055

    
3056
		/* group by interface */
3057
		foreach ($config['virtualip']['vip'] as $vipent) {
3058
			if ($vipent['mode'] === "proxyarp") {
3059
				if ($vipent['interface']) {
3060
					$proxyif = $vipent['interface'];
3061
				} else {
3062
					$proxyif = "wan";
3063
				}
3064

    
3065
				if (!empty($interface) && $interface != $proxyif) {
3066
					continue;
3067
				}
3068

    
3069
				if (!is_array($paa[$proxyif])) {
3070
					$paa[$proxyif] = array();
3071
				}
3072

    
3073
				$paa[$proxyif][] = $vipent;
3074
			}
3075
		}
3076
	}
3077

    
3078
	if (!empty($interface)) {
3079
		if (is_array($paa[$interface])) {
3080
			$paaifip = get_interface_ip($interface);
3081
			if (!is_ipaddr($paaifip)) {
3082
				return;
3083
			}
3084
			$vipif = get_real_interface($interface);
3085
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
3086
			$args .= $vipif . " auto";
3087
			foreach ($paa[$interface] as $paent) {
3088
				if (isset($paent['subnet'])) {
3089
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
3090
				} elseif (isset($paent['range'])) {
3091
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
3092
				}
3093
			}
3094
			mwexec_bg("/usr/local/sbin/choparp " . $args);
3095
		}
3096
	} elseif (count($paa) > 0) {
3097
		foreach ($paa as $paif => $paents) {
3098
			$paaifip = get_interface_ip($paif);
3099
			if (!is_ipaddr($paaifip)) {
3100
				continue;
3101
			}
3102
			$vipif = get_real_interface($paif);
3103
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
3104
			$args .= $vipif . " auto";
3105
			foreach ($paents as $paent) {
3106
				if (isset($paent['subnet'])) {
3107
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
3108
				} elseif (isset($paent['range'])) {
3109
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
3110
				}
3111
			}
3112
			mwexec_bg("/usr/local/sbin/choparp " . $args);
3113
		}
3114
	}
3115
}
3116

    
3117
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
3118
	global $g, $config;
3119

    
3120
	if (is_array($config['virtualip']['vip'])) {
3121
		foreach ($config['virtualip']['vip'] as $vip) {
3122

    
3123
			$iface = $vip['interface'];
3124
			if (substr($iface, 0, 4) == "_vip")
3125
				$iface = get_configured_vip_interface($vip['interface']);
3126
			if ($iface != $interface)
3127
				continue;
3128
			if ($type == VIP_CARP) {
3129
				if ($vip['mode'] != "carp")
3130
					continue;
3131
			} elseif ($type == VIP_IPALIAS) {
3132
				if ($vip['mode'] != "ipalias")
3133
					continue;
3134
			} else {
3135
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
3136
					continue;
3137
			}
3138

    
3139
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
3140
				interface_vip_bring_down($vip);
3141
			elseif ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
3142
				interface_vip_bring_down($vip);
3143
			elseif ($inet == "all")
3144
				interface_vip_bring_down($vip);
3145
		}
3146
	}
3147
}
3148

    
3149
function interfaces_vips_configure($interface = "") {
3150
	global $g, $config;
3151
	if (isset($config['system']['developerspew'])) {
3152
		$mt = microtime();
3153
		echo "interfaces_vips_configure() being called $mt\n";
3154
	}
3155

    
3156
	if (!is_array($config['virtualip']['vip'])) {
3157
		return;
3158
	}
3159

    
3160
	$carp_setuped = false;
3161
	$anyproxyarp = false;
3162
	foreach ($config['virtualip']['vip'] as $vip) {
3163
		if ($interface <> "" &&
3164
		    get_root_interface($vip['interface']) <> $interface) {
3165
			continue;
3166
		}
3167
		switch ($vip['mode']) {
3168
			case "proxyarp":
3169
				/*
3170
				 * nothing it is handled on
3171
				 * interface_proxyarp_configure()
3172
				 */
3173
				$anyproxyarp = true;
3174
				break;
3175
			case "ipalias":
3176
				interface_ipalias_configure($vip);
3177
				break;
3178
			case "carp":
3179
				if ($carp_setuped == false) {
3180
					$carp_setuped = true;
3181
				}
3182
				interface_carp_configure($vip);
3183
				break;
3184
		}
3185
	}
3186
	if ($carp_setuped == true) {
3187
		interfaces_sync_setup();
3188
	}
3189
	if ($anyproxyarp == true) {
3190
		interface_proxyarp_configure();
3191
	}
3192
}
3193

    
3194
function interface_ipalias_configure(&$vip) {
3195
	global $config;
3196

    
3197
	$gateway = '';
3198
	if ($vip['mode'] != 'ipalias') {
3199
		return;
3200
	}
3201

    
3202
	$realif = get_real_interface("_vip{$vip['uniqid']}");
3203
	if ($realif != "lo0") {
3204
		$if = convert_real_interface_to_friendly_interface_name($realif);
3205
		if (!isset($config['interfaces'][$if]) ||
3206
		    !isset($config['interfaces'][$if]['enable'])) {
3207
			return;
3208
		}
3209
		if (is_pseudo_interface($realif)) {
3210
			if (is_ipaddrv4($vip['subnet'])) {
3211
				$gateway = get_interface_gateway($if);
3212
			} else {
3213
				$gateway = get_interface_gateway_v6($if);
3214
			}
3215
		}
3216
	}
3217

    
3218
	$af = 'inet';
3219
	if (is_ipaddrv6($vip['subnet'])) {
3220
		$af = 'inet6';
3221
	}
3222
	$iface = $vip['interface'];
3223
	$vhid = '';
3224
	if (substr($vip['interface'], 0, 4) == "_vip") {
3225
		$carpvip = get_configured_vip($vip['interface']);
3226
		$iface = $carpvip['interface'];
3227
		$vhid = "vhid {$carpvip['vhid']}";
3228
	}
3229
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$gateway} {$vhid}");
3230
	unset($iface, $af, $realif, $carpvip, $vhid, $gateway);
3231
}
3232

    
3233
function interface_carp_configure(&$vip, $maintenancemode_only = false) {
3234
	global $config, $g;
3235
	if (isset($config['system']['developerspew'])) {
3236
		$mt = microtime();
3237
		echo "interface_carp_configure() being called $mt\n";
3238
	}
3239

    
3240
	if ($vip['mode'] != "carp") {
3241
		return;
3242
	}
3243

    
3244
	$realif = get_real_interface($vip['interface']);
3245
	if (!does_interface_exist($realif)) {
3246
		file_notice("CARP", sprintf(gettext(
3247
		    "Interface specified for the virtual IP address %s does not exist. Skipping this VIP."),
3248
		    $vip['subnet']), "Firewall: Virtual IP", "");
3249
		return;
3250
	}
3251
	if ($realif != "lo0") {
3252
		if (!isset($config['interfaces'][$vip['interface']]) ||
3253
		    !isset($config['interfaces'][$vip['interface']]['enable'])) {
3254
			return;
3255
		}
3256
	}
3257

    
3258
	$vip_password = $vip['password'];
3259
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3260
	    $vip_password)));
3261
	if ($vip['password'] != "") {
3262
		$password = " pass {$vip_password}";
3263
	}
3264

    
3265
	$advbase = "";
3266
	if (!empty($vip['advbase'])) {
3267
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3268
	}
3269

    
3270
	$carp_maintenancemode = isset(
3271
	    $config["virtualip_carp_maintenancemode"]);
3272
	if ($carp_maintenancemode) {
3273
		$advskew = "advskew 254";
3274
	} else {
3275
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3276
	}
3277

    
3278
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) .
3279
	    " {$advskew} {$advbase} {$password}");
3280

    
3281
	if (!$maintenancemode_only) {
3282
		if (is_ipaddrv4($vip['subnet'])) {
3283
			mwexec("/sbin/ifconfig {$realif} " .
3284
			    escapeshellarg($vip['subnet']) . "/" .
3285
			    escapeshellarg($vip['subnet_bits']) .
3286
			    " alias vhid " . escapeshellarg($vip['vhid']));
3287
		} elseif (is_ipaddrv6($vip['subnet'])) {
3288
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3289
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3290
			    escapeshellarg($vip['subnet_bits']) .
3291
			    " alias vhid " . escapeshellarg($vip['vhid']));
3292
		}
3293
	}
3294

    
3295
	return $realif;
3296
}
3297

    
3298
function interface_wireless_clone($realif, $wlcfg) {
3299
	global $config, $g;
3300
	/*   Check to see if interface has been cloned as of yet.
3301
	 *   If it has not been cloned then go ahead and clone it.
3302
	 */
3303
	$needs_clone = false;
3304
	if (is_array($wlcfg['wireless'])) {
3305
		$wlcfg_mode = $wlcfg['wireless']['mode'];
3306
	} else {
3307
		$wlcfg_mode = $wlcfg['mode'];
3308
	}
3309
	switch ($wlcfg_mode) {
3310
		case "hostap":
3311
			$mode = "wlanmode hostap";
3312
			break;
3313
		case "adhoc":
3314
			$mode = "wlanmode adhoc";
3315
			break;
3316
		default:
3317
			$mode = "";
3318
			break;
3319
	}
3320
	$baseif = interface_get_wireless_base($wlcfg['if']);
3321
	if (does_interface_exist($realif)) {
3322
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
3323
		$ifconfig_str = implode($output);
3324
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
3325
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
3326
			$needs_clone = true;
3327
		}
3328
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
3329
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
3330
			$needs_clone = true;
3331
		}
3332
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
3333
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
3334
			$needs_clone = true;
3335
		}
3336
	} else {
3337
		$needs_clone = true;
3338
	}
3339

    
3340
	if ($needs_clone == true) {
3341
		/* remove previous instance if it exists */
3342
		if (does_interface_exist($realif)) {
3343
			pfSense_interface_destroy($realif);
3344

    
3345
			/* Invalidate cache */
3346
			get_interface_arr(true);
3347
		}
3348

    
3349
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
3350
		// Create the new wlan interface. FreeBSD returns the new interface name.
3351
		// example:  wlan2
3352
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
3353
		if ($ret <> 0) {
3354
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
3355
			return false;
3356
		}
3357
		$newif = trim($out[0]);
3358
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
3359
		pfSense_interface_rename($newif, $realif);
3360
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
3361
	}
3362
	return true;
3363
}
3364

    
3365
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3366
	global $config, $g;
3367

    
3368
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3369
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3370
				 'regdomain', 'regcountry', 'reglocation');
3371

    
3372
	if (!is_interface_wireless($ifcfg['if'])) {
3373
		return;
3374
	}
3375

    
3376
	$baseif = interface_get_wireless_base($ifcfg['if']);
3377

    
3378
	// Sync shared settings for assigned clones
3379
	$iflist = get_configured_interface_list(true);
3380
	foreach ($iflist as $if) {
3381
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
3382
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
3383
				foreach ($shared_settings as $setting) {
3384
					if ($sync_changes) {
3385
						if (isset($ifcfg['wireless'][$setting])) {
3386
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
3387
						} elseif (isset($config['interfaces'][$if]['wireless'][$setting])) {
3388
							unset($config['interfaces'][$if]['wireless'][$setting]);
3389
						}
3390
					} else {
3391
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3392
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
3393
						} elseif (isset($ifcfg['wireless'][$setting])) {
3394
							unset($ifcfg['wireless'][$setting]);
3395
						}
3396
					}
3397
				}
3398
				if (!$sync_changes) {
3399
					break;
3400
				}
3401
			}
3402
		}
3403
	}
3404

    
3405
	// Read or write settings at shared area
3406
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
3407
		foreach ($shared_settings as $setting) {
3408
			if ($sync_changes) {
3409
				if (isset($ifcfg['wireless'][$setting])) {
3410
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
3411
				} elseif (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3412
					unset($config['wireless']['interfaces'][$baseif][$setting]);
3413
				}
3414
			} elseif (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3415
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3416
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
3417
				} elseif (isset($ifcfg['wireless'][$setting])) {
3418
					unset($ifcfg['wireless'][$setting]);
3419
				}
3420
			}
3421
		}
3422
	}
3423

    
3424
	// Sync the mode on the clone creation page with the configured mode on the interface
3425
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3426
		foreach ($config['wireless']['clone'] as &$clone) {
3427
			if ($clone['cloneif'] == $ifcfg['if']) {
3428
				if ($sync_changes) {
3429
					$clone['mode'] = $ifcfg['wireless']['mode'];
3430
				} else {
3431
					$ifcfg['wireless']['mode'] = $clone['mode'];
3432
				}
3433
				break;
3434
			}
3435
		}
3436
		unset($clone);
3437
	}
3438
}
3439

    
3440
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3441
	global $config, $g;
3442

    
3443
	/*    open up a shell script that will be used to output the commands.
3444
	 *    since wireless is changing a lot, these series of commands are fragile
3445
	 *    and will sometimes need to be verified by a operator by executing the command
3446
	 *    and returning the output of the command to the developers for inspection.  please
3447
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3448
	 */
3449

    
3450
	// Remove script file
3451
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3452

    
3453
	// Clone wireless nic if needed.
3454
	interface_wireless_clone($if, $wl);
3455

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

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

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

    
3465
	/* set values for /path/program */
3466
	if (file_exists("/usr/local/sbin/hostapd")) {
3467
		$hostapd = "/usr/local/sbin/hostapd";
3468
	} else {
3469
		$hostapd = "/usr/sbin/hostapd";
3470
	}
3471
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3472
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3473
	} else {
3474
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3475
	}
3476
	$ifconfig = "/sbin/ifconfig";
3477
	$sysctl = "/sbin/sysctl";
3478
	$sysctl_args = "-q";
3479
	$killall = "/usr/bin/killall";
3480

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

    
3483
	$wlcmd = array();
3484
	$wl_sysctl = array();
3485
	/* Set a/b/g standard */
3486
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3487
	/* skip mode entirely for "auto" */
3488
	if ($wlcfg['standard'] != "auto") {
3489
		$wlcmd[] = "mode " . escapeshellarg($standard);
3490
	}
3491

    
3492
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3493
	 * to prevent massive packet loss under certain conditions. */
3494
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3495
		$wlcmd[] = "-ampdu";
3496
	}
3497

    
3498
	/* Set ssid */
3499
	if ($wlcfg['ssid']) {
3500
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3501
	}
3502

    
3503
	/* Set 802.11g protection mode */
3504
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3505

    
3506
	/* set wireless channel value */
3507
	if (isset($wlcfg['channel'])) {
3508
		if ($wlcfg['channel'] == "0") {
3509
			$wlcmd[] = "channel any";
3510
		} else {
3511
			if ($wlcfg['channel_width'] != "0") {
3512
				$channel_width = ":" . $wlcfg['channel_width'];
3513
			} else {
3514
				$channel_width = '';
3515
			}
3516
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3517
		}
3518
	}
3519

    
3520
	/* Set antenna diversity value */
3521
	if (isset($wlcfg['diversity'])) {
3522
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3523
	}
3524

    
3525
	/* Set txantenna value */
3526
	if (isset($wlcfg['txantenna'])) {
3527
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3528
	}
3529

    
3530
	/* Set rxantenna value */
3531
	if (isset($wlcfg['rxantenna'])) {
3532
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3533
	}
3534

    
3535
	/* set Distance value */
3536
	if ($wlcfg['distance']) {
3537
		$distance = escapeshellarg($wlcfg['distance']);
3538
	}
3539

    
3540
	/* Set wireless hostap mode */
3541
	if ($wlcfg['mode'] == "hostap") {
3542
		$wlcmd[] = "mediaopt hostap";
3543
	} else {
3544
		$wlcmd[] = "-mediaopt hostap";
3545
	}
3546

    
3547
	/* Set wireless adhoc mode */
3548
	if ($wlcfg['mode'] == "adhoc") {
3549
		$wlcmd[] = "mediaopt adhoc";
3550
	} else {
3551
		$wlcmd[] = "-mediaopt adhoc";
3552
	}
3553

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

    
3556
	/* handle hide ssid option */
3557
	if (isset($wlcfg['hidessid']['enable'])) {
3558
		$wlcmd[] = "hidessid";
3559
	} else {
3560
		$wlcmd[] = "-hidessid";
3561
	}
3562

    
3563
	/* handle pureg (802.11g) only option */
3564
	if (isset($wlcfg['pureg']['enable'])) {
3565
		$wlcmd[] = "mode 11g pureg";
3566
	} else {
3567
		$wlcmd[] = "-pureg";
3568
	}
3569

    
3570
	/* handle puren (802.11n) only option */
3571
	if (isset($wlcfg['puren']['enable'])) {
3572
		$wlcmd[] = "puren";
3573
	} else {
3574
		$wlcmd[] = "-puren";
3575
	}
3576

    
3577
	/* enable apbridge option */
3578
	if (isset($wlcfg['apbridge']['enable'])) {
3579
		$wlcmd[] = "apbridge";
3580
	} else {
3581
		$wlcmd[] = "-apbridge";
3582
	}
3583

    
3584
	/* handle turbo option */
3585
	if (isset($wlcfg['turbo']['enable'])) {
3586
		$wlcmd[] = "mediaopt turbo";
3587
	} else {
3588
		$wlcmd[] = "-mediaopt turbo";
3589
	}
3590

    
3591
	/* handle txpower setting */
3592
	// or don't. this has issues at the moment.
3593
	/*
3594
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3595
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3596
	}*/
3597

    
3598
	/* handle wme option */
3599
	if (isset($wlcfg['wme']['enable'])) {
3600
		$wlcmd[] = "wme";
3601
	} else {
3602
		$wlcmd[] = "-wme";
3603
	}
3604

    
3605
	/* Enable wpa if it's configured. No WEP support anymore. */
3606
	if (isset($wlcfg['wpa']['enable'])) {
3607
		$wlcmd[] = "authmode wpa wepmode off ";
3608
	} else {
3609
		$wlcmd[] = "authmode open wepmode off ";
3610
	}
3611

    
3612
	kill_hostapd($if);
3613
	mwexec(kill_wpasupplicant("{$if}"));
3614

    
3615
	$wpa_supplicant_file = "{$g['varetc_path']}/wpa_supplicant_{$if}.";
3616
	$hostapd_conf = "{$g['varetc_path']}/hostapd_{$if}.conf";
3617

    
3618
	unlink_if_exists("{$wpa_supplicant_file}*");
3619
	unlink_if_exists($hostapd_conf);
3620

    
3621
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3622

    
3623
	switch ($wlcfg['mode']) {
3624
		case 'bss':
3625
			if (isset($wlcfg['wpa']['enable'])) {
3626
				$wpa .= <<<EOD
3627
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3628
ctrl_interface_group=0
3629
ap_scan=1
3630
#fast_reauth=1
3631
network={
3632
ssid="{$wlcfg['ssid']}"
3633
scan_ssid=1
3634
priority=5
3635
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3636
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3637
group={$wlcfg['wpa']['wpa_pairwise']}
3638

    
3639
EOD;
3640
				if ($wlcfg['wpa']['wpa_key_mgmt'] == 'WPA-EAP') {
3641
					if (($wlcfg['wpa']['wpa_eap_client_mode'] == 'PEAP') ||
3642
					    ($wlcfg['wpa']['wpa_eap_client_mode'] == 'TTLS')) {
3643
						if ($wlcfg['wpa']['wpa_eap_inner_auth'] == 'MSCHAPV2') {
3644
							$wpa .= "phase1=\"peaplabel=0\"\n";
3645
						}
3646
						$wpa .= "phase2=\"auth={$wlcfg['wpa']['wpa_eap_inner_auth']}\"\n";
3647
						$wpa .= "identity=\"{$wlcfg['wpa']['wpa_eap_inner_id']}\"\n";
3648
						$eappass = base64_decode($wlcfg['wpa']['wpa_eap_inner_password']);
3649
						$wpa .= "password=\"{$eappass}\"\n";
3650
					}
3651
					if (strstr($wlcfg['wpa']['wpa_eap_client_mode'], 'TLS')) { 
3652
						$cert = lookup_cert($wlcfg['wpa']['wpa_eap_cert']);
3653
						@file_put_contents($wpa_supplicant_file . "crt", base64_decode($cert['crt']) . "\n" .
3654
						    ca_chain($cert)); 
3655
						@file_put_contents($wpa_supplicant_file . "key", base64_decode($cert['prv'])); 
3656
						@chmod($wpa_supplicant_crt, 0600);
3657
						@chmod($wpa_supplicant_key, 0600);
3658
						$wpa .= "client_cert=\"{$wpa_supplicant_crt}\"\n";
3659
						$wpa .= "private_key=\"{$wpa_supplicant_key}\"\n";
3660
					}
3661
					$ca = lookup_ca($wlcfg['wpa']['wpa_eap_ca']);
3662
					@file_put_contents($wpa_supplicant_file . "ca", base64_decode($ca['crt']) . "\n" .
3663
					    ca_chain($ca)); 
3664
					$wpa .= "ca_cert=\"{$wpa_supplicant_ca}\"\n";
3665
					$wpa .= "eap={$wlcfg['wpa']['wpa_eap_client_mode']}\n";
3666
				} else {
3667
					$wpa .= "psk=\"{$wlcfg['wpa']['passphrase']}\"\n";
3668
				}
3669
				$wpa .= "}\n";
3670

    
3671
				@file_put_contents($wpa_supplicant_file . "conf", $wpa);
3672
				unset($wpa);
3673
			}
3674
			break;
3675
		case 'hostap':
3676
			if (!empty($wlcfg['wpa']['passphrase'])) {
3677
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3678
			} else {
3679
				$wpa_passphrase = "";
3680
			}
3681
			if (isset($wlcfg['wpa']['enable'])) {
3682
				$wpa .= <<<EOD
3683
interface={$if}
3684
driver=bsd
3685
logger_syslog=-1
3686
logger_syslog_level=0
3687
logger_stdout=-1
3688
logger_stdout_level=0
3689
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3690
ctrl_interface={$g['varrun_path']}/hostapd
3691
ctrl_interface_group=wheel
3692
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3693
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3694
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3695
ssid={$wlcfg['ssid']}
3696
debug={$wlcfg['wpa']['debug_mode']}
3697
wpa={$wlcfg['wpa']['wpa_mode']}
3698
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3699
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3700
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3701
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3702
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3703
{$wpa_passphrase}
3704

    
3705
EOD;
3706

    
3707
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3708
					$wpa .= <<<EOD
3709
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3710
rsn_preauth=1
3711
rsn_preauth_interfaces={$if}
3712

    
3713
EOD;
3714
				}
3715
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3716
					$wpa .= "ieee8021x=1\n";
3717

    
3718
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3719
						$auth_server_port = "1812";
3720
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3721
							$auth_server_port = intval($wlcfg['auth_server_port']);
3722
						}
3723
						$wpa .= <<<EOD
3724

    
3725
auth_server_addr={$wlcfg['auth_server_addr']}
3726
auth_server_port={$auth_server_port}
3727
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3728

    
3729
EOD;
3730
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3731
							$auth_server_port2 = "1812";
3732
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3733
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3734
							}
3735

    
3736
							$wpa .= <<<EOD
3737
auth_server_addr={$wlcfg['auth_server_addr2']}
3738
auth_server_port={$auth_server_port2}
3739
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3740

    
3741
EOD;
3742
						}
3743
					}
3744
				}
3745

    
3746
				@file_put_contents($hostapd_conf, $wpa);
3747
				unset($wpa);
3748
			}
3749
			break;
3750
	}
3751

    
3752
	/*
3753
	 *    all variables are set, lets start up everything
3754
	 */
3755

    
3756
	$baseif = interface_get_wireless_base($if);
3757
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3758
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3759

    
3760
	/* set sysctls for the wireless interface */
3761
	if (!empty($wl_sysctl)) {
3762
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3763
		foreach ($wl_sysctl as $wl_sysctl_line) {
3764
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3765
		}
3766
	}
3767

    
3768
	/* set ack timers according to users preference (if he/she has any) */
3769
	if ($distance) {
3770
		fwrite($fd_set, "# Enable ATH distance settings\n");
3771
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3772
	}
3773

    
3774
	if (isset($wlcfg['wpa']['enable'])) {
3775
		if ($wlcfg['mode'] == "bss") {
3776
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3777
		}
3778
		if ($wlcfg['mode'] == "hostap") {
3779
			/* add line to script to restore old mac to make hostapd happy */
3780
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3781
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3782
				$if_curmac = get_interface_mac($if);
3783
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3784
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3785
						" link " . escapeshellarg($if_oldmac) . "\n");
3786
				}
3787
			}
3788

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

    
3791
			/* add line to script to restore spoofed mac after running hostapd */
3792
			if ($wl['spoofmac']) {
3793
				$if_curmac = get_interface_mac($if);
3794
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3795
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3796
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3797
				}
3798
			}
3799
		}
3800
	}
3801

    
3802
	fclose($fd_set);
3803

    
3804
	/* Making sure regulatory settings have actually changed
3805
	 * before applying, because changing them requires bringing
3806
	 * down all wireless networks on the interface. */
3807
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3808
	$ifconfig_str = implode($output);
3809
	unset($output);
3810
	$reg_changing = false;
3811

    
3812
	/* special case for the debug country code */
3813
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3814
		$reg_changing = true;
3815
	} elseif ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3816
		$reg_changing = true;
3817
	} elseif ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3818
		$reg_changing = true;
3819
	} elseif ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3820
		$reg_changing = true;
3821
	} elseif ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3822
		$reg_changing = true;
3823
	}
3824

    
3825
	if ($reg_changing) {
3826
		/* set regulatory domain */
3827
		if ($wlcfg['regdomain']) {
3828
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3829
		}
3830

    
3831
		/* set country */
3832
		if ($wlcfg['regcountry']) {
3833
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3834
		}
3835

    
3836
		/* set location */
3837
		if ($wlcfg['reglocation']) {
3838
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3839
		}
3840

    
3841
		$wlregcmd_args = implode(" ", $wlregcmd);
3842

    
3843
		/* build a complete list of the wireless clones for this interface */
3844
		$clone_list = array();
3845
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3846
			$clone_list[] = interface_get_wireless_clone($baseif);
3847
		}
3848
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3849
			foreach ($config['wireless']['clone'] as $clone) {
3850
				if ($clone['if'] == $baseif) {
3851
					$clone_list[] = $clone['cloneif'];
3852
				}
3853
			}
3854
		}
3855

    
3856
		/* find which clones are up and bring them down */
3857
		$clones_up = array();
3858
		foreach ($clone_list as $clone_if) {
3859
			$clone_status = pfSense_get_interface_addresses($clone_if);
3860
			if ($clone_status['status'] == 'up') {
3861
				$clones_up[] = $clone_if;
3862
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3863
			}
3864
		}
3865

    
3866
		/* apply the regulatory settings */
3867
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3868
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3869

    
3870
		/* bring the clones back up that were previously up */
3871
		foreach ($clones_up as $clone_if) {
3872
			interfaces_bring_up($clone_if);
3873

    
3874
			/*
3875
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3876
			 * is in infrastructure mode, and WPA is enabled.
3877
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3878
			 */
3879
			if ($clone_if != $if) {
3880
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3881
				if ((!empty($friendly_if)) &&
3882
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3883
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3884
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3885
				}
3886
			}
3887
		}
3888
	}
3889

    
3890
	/* The mode must be specified in a separate command before ifconfig
3891
	 * will allow the mode and channel at the same time in the next.
3892
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3893
	 */
3894
	if ($wlcfg['mode'] == "hostap") {
3895
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3896
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3897
	}
3898

    
3899
	/* configure wireless */
3900
	$wlcmd_args = implode(" ", $wlcmd);
3901
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args);
3902
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3903
	/* Bring the interface up only after setting up all the other parameters. */
3904
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up");
3905
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3906
	fclose($wlan_setup_log);
3907

    
3908
	unset($wlcmd_args, $wlcmd);
3909

    
3910

    
3911
	sleep(1);
3912
	/* execute hostapd and wpa_supplicant if required in shell */
3913
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3914

    
3915
	return 0;
3916

    
3917
}
3918

    
3919
function kill_hostapd($interface) {
3920
	global $g;
3921

    
3922
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3923
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3924
	}
3925
}
3926

    
3927
function kill_wpasupplicant($interface) {
3928
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3929
}
3930

    
3931
function find_dhclient_process($interface) {
3932
	if ($interface) {
3933
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3934
	} else {
3935
		$pid = 0;
3936
	}
3937

    
3938
	return intval($pid);
3939
}
3940

    
3941
function kill_dhclient_process($interface) {
3942
	if (empty($interface) || !does_interface_exist($interface)) {
3943
		return;
3944
	}
3945

    
3946
	$i = 0;
3947
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3948
		/* 3rd time make it die for sure */
3949
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3950
		posix_kill($pid, $sig);
3951
		sleep(1);
3952
		$i++;
3953
	}
3954
	unset($i);
3955
}
3956

    
3957
function find_dhcp6c_process($interface) {
3958
	global $g;
3959

    
3960
	if ($interface && isvalidpid("{$g['varrun_path']}/dhcp6c_{$interface}.pid")) {
3961
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c_{$interface}.pid"), " \n");
3962
	} else {
3963
		return(false);
3964
	}
3965

    
3966
	return intval($pid);
3967
}
3968

    
3969
function kill_dhcp6client_process($interface, $force, $release = false) {
3970
	global $g;
3971

    
3972
	$i = 0;
3973

    
3974
	/*
3975
	Beware of the following: Reason, the interface may be down, but
3976
	dhcp6c may still be running, it just complains it cannot send
3977
	and carries on. Commented out as will stop the call to kill.
3978

    
3979
	if (empty($interface) || !does_interface_exist($interface)) {
3980
		return;
3981
	}
3982
	*/
3983

    
3984
	/*********** Notes on signals for dhcp6c and this function *************
3985

    
3986
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3987
	a release and waiting for the response that never comes.
3988
	So we need to tell it that the interface is down and to just die quickly
3989
	otherwise a new client may launch and we have duplicate proceses.
3990
	In this case use SIGUSR1.
3991

    
3992
	If we want to exit normally obeying the no release flag then use SIGTERM.
3993
	If we want to exit with a release overiding the no release flag then
3994
	use SIGUSR2.
3995

    
3996
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3997
	exit quickly without sending release signals.
3998

    
3999
	If $Force is set to false and $release is also set to false dhcp6c will
4000
	follow the no-release flag.
4001

    
4002
	If $Force is set to false and $release is true then dhcp6c will send a
4003
	release regardless of the no-release flag.
4004
	***********************************************************************/
4005

    
4006
	if ($force == true) {
4007
		$psig=SIGUSR1;
4008
	} elseif ($release == false) {
4009
		$psig=SIGTERM;
4010
	} else {
4011
		$psig=SIGUSR2;
4012
	}
4013

    
4014
	while ((($pid = find_dhcp6c_process($interface)) != 0) && ($i < 3)) {
4015
		/* 3rd time make it die for sure */
4016
		$sig = ($i == 2 ? SIGKILL : $psig);
4017
		posix_kill($pid, $sig);
4018
		sleep(1);
4019
		$i++;
4020
	}
4021
	/* Clear the RTSOLD script created lock & tidy up */
4022
	unlink_if_exists("/tmp/dhcp6c_{$interface}_lock");
4023
	unlink_if_exists("{$g['varrun_path']}/dhcp6c_{$interface}.pid"); // just in case!
4024
}
4025
function reset_dhcp6client_process($interface) {
4026

    
4027
	$pid = find_dhcp6c_process($interface);
4028

    
4029
	if($pid != 0) {
4030
		posix_kill($pid, SIGHUP);
4031
	}
4032
}
4033

    
4034
function run_dhcp6client_process($interface, $interface_name, $wancfg) {
4035
	global $g;
4036

    
4037
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
4038
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
4039

    
4040
	/*
4041
	 * Only run this if the lock does not exist. In theory the lock being
4042
	 * there in this mode means the user has selected dhcp6withoutRA while
4043
	 * a session is active in the other mode.
4044
	 *
4045
	 * It should not happen as the process should have been killed and the
4046
	 * lock deleted.
4047
	 */
4048

    
4049
	if (!file_exists("/tmp/dhcp6c_{$interface}_lock")) {
4050
		kill_dhcp6client_process($interface, true);
4051
		/* Lock it to avoid multiple runs */
4052
		touch("/tmp/dhcp6c_{$interface}_lock");
4053
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
4054
		    "{$noreleaseOption} " .
4055
		    "-c {$g['varetc_path']}/dhcp6c_{$interface_name}.conf " .
4056
		    "-p {$g['varrun_path']}/dhcp6c_{$interface}.pid " .
4057
		    $interface);
4058
		log_error(sprintf(gettext(
4059
		    "Starting dhcp6 client for interface wan %s in DHCP6 without RA mode"),
4060
		    $interface));
4061
	}
4062
}
4063

    
4064
function interface_virtual_create($interface) {
4065
	global $config;
4066

    
4067
	if (interface_is_vlan($interface) != NULL) {
4068
		interface_vlan_configure(interface_is_vlan($interface));
4069
	} elseif (substr($interface, 0, 3) == "gre") {
4070
		interfaces_tunnel_configure(0, $interface, 'gre');
4071
	} elseif (substr($interface, 0, 3) == "gif") {
4072
		interfaces_tunnel_configure(0, $interface, 'gif');
4073
	} elseif (substr($interface, 0, 5) == "ovpns") {
4074
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
4075
			foreach ($config['openvpn']['openvpn-server'] as $server) {
4076
				if ($interface == "ovpns{$server['vpnid']}") {
4077
					if (!function_exists('openvpn_resync')) {
4078
						require_once('openvpn.inc');
4079
					}
4080
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
4081
					openvpn_resync('server', $server);
4082
				}
4083
			}
4084
			unset($server);
4085
		}
4086
	} elseif (substr($interface, 0, 5) == "ovpnc") {
4087
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
4088
			foreach ($config['openvpn']['openvpn-client'] as $client) {
4089
				if ($interface == "ovpnc{$client['vpnid']}") {
4090
					if (!function_exists('openvpn_resync')) {
4091
						require_once('openvpn.inc');
4092
					}
4093
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
4094
					openvpn_resync('client', $client);
4095
				}
4096
			}
4097
			unset($client);
4098
		}
4099
	} elseif (substr($interface, 0, 5) == "ipsec") {
4100
		if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
4101
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
4102
				if ($ph1ent['disabled']) {
4103
					continue;
4104
				}
4105
				if ($interface == "ipsec{$ph1ent['ikeid']}") {
4106
					interface_ipsec_vti_configure($ph1ent);
4107
				}
4108
			}
4109
		}
4110
	} elseif (substr($interface, 0, 4) == "lagg") {
4111
		interfaces_lagg_configure($interface);
4112
	} elseif (substr($interface, 0, 6) == "bridge") {
4113
		interfaces_bridge_configure(0, $interface);
4114
	}
4115
}
4116

    
4117
function interface_vlan_mtu_configured($iface) {
4118
	global $config;
4119

    
4120
	$mtu = 0;
4121
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
4122
		foreach ($config['vlans']['vlan'] as $vlan) {
4123

    
4124
			if ($vlan['vlanif'] != $iface)
4125
				continue;
4126

    
4127
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4128
			$parentinf = convert_real_interface_to_friendly_interface_name($vlan['if']);
4129
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
4130
				/* VLAN MTU */
4131
				$mtu = $config['interfaces'][$assignedport]['mtu'];
4132
			} elseif (!empty($config['interfaces'][$parentinf]['mtu'])) {
4133
				/* Parent MTU */
4134
				$mtu = $config['interfaces'][$parentinf]['mtu'];
4135
			}
4136
		}
4137
	}
4138

    
4139
	return $mtu;
4140
}
4141

    
4142
function interface_mtu_wanted_for_pppoe($realif) {
4143
	global $config;
4144

    
4145
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
4146
		return 0;
4147

    
4148
	$mtu = 0;
4149
	foreach ($config['ppps']['ppp'] as $ppp) {
4150
		if ($ppp['type'] != "pppoe") {
4151
			continue;
4152
		}
4153

    
4154
		$mtus = array();
4155
		if (!empty($ppp['mtu'])) {
4156
			$mtus = explode(',', $ppp['mtu']);
4157
		}
4158
		$ports = explode(',', $ppp['ports']);
4159

    
4160
		foreach ($ports as $pid => $port) {
4161
			$parentifa = get_parent_interface($port);
4162
			$parentif = $parentifa[0];
4163
			if ($parentif != $realif)
4164
				continue;
4165

    
4166
			// there is an MTU configured on the port in question
4167
			if (!empty($mtus[$pid])) {
4168
				$mtu = intval($mtus[$pid]) + 8;
4169
			// or use the MTU configured on the interface ...
4170
			} elseif (is_array($config['interfaces'])) {
4171
				foreach ($config['interfaces'] as $interface) {
4172
					if ($interface['if'] == $ppp['if'] &&
4173
					    !empty($interface['mtu'])) {
4174
						$mtu = intval($interface['mtu']) + 8;
4175
						break;
4176
					}
4177
				}
4178
			}
4179
		}
4180
	}
4181

    
4182
	return $mtu;
4183
}
4184

    
4185
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
4186
	global $config, $g;
4187
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
4188
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
4189

    
4190
	$wancfg = $config['interfaces'][$interface];
4191

    
4192
	if (!isset($wancfg['enable'])) {
4193
		return;
4194
	}
4195

    
4196
	if (substr($config['interfaces'][$interface]['if'], 0, 2) == 'wg') {
4197
		require_once('wg.inc');
4198
		wg_configure_if($config['interfaces'][$interface]['if']);
4199
	}
4200

    
4201
	$realif = get_real_interface($interface);
4202
	$realhwif_array = get_parent_interface($interface);
4203
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
4204
	$realhwif = $realhwif_array[0];
4205

    
4206
	$mac_if_cfg = $wancfg;
4207
	if (interface_is_vlan($realif)) {
4208
		$mac_if = convert_real_interface_to_friendly_interface_name(
4209
		    $realhwif);
4210
		if (is_array($config['interfaces'][$mac_if])) {
4211
			$mac_if_cfg = $config['interfaces'][$mac_if];
4212
		} else {
4213
			$mac_if = $interface;
4214
		}
4215
	}
4216

    
4217
	if (!platform_booting() &&
4218
	    (substr($realif, 0, 4) != "ovpn") &&
4219
	    (substr($realif, 0, 5) != "ipsec") &&
4220
	    (substr($realif, 0, 2) != "wg")) {
4221
		/* remove all IPv4 and IPv6 addresses */
4222
		$tmpifaces = pfSense_getall_interface_addresses($realif);
4223
		if (is_array($tmpifaces)) {
4224
			foreach ($tmpifaces as $tmpiface) {
4225
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
4226
					if (!is_linklocal($tmpiface)) {
4227
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
4228
					}
4229
				} elseif (strstr($tmpiface, "fe80::1:1")) {
4230
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 fe80::1:1 -alias");
4231
				} else {
4232
					if (is_subnetv4($tmpiface)) {
4233
						$tmpip = explode('/', $tmpiface);
4234
						$tmpip = $tmpip[0];
4235
					} else {
4236
						$tmpip = $tmpiface;
4237
					}
4238
					pfSense_interface_deladdress($realif, $tmpip);
4239
				}
4240
			}
4241
		}
4242

    
4243
		/* only bring down the interface when both v4 and v6 are set to NONE */
4244
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
4245
			interface_bring_down($interface);
4246
		}
4247
	}
4248

    
4249
	$interface_to_check = $realif;
4250
	if (interface_isppp_type($interface)) {
4251
		$interface_to_check = $realhwif;
4252
	}
4253

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

    
4259
	/* Disable Accepting router advertisements unless specifically requested */
4260
	if ($g['debug']) {
4261
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
4262
	}
4263
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
4264
	{
4265
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
4266
	}
4267
	/* wireless configuration? */
4268
	if (is_array($wancfg['wireless']) && !$linkupevent) {
4269
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
4270
	}
4271

    
4272
	$current_mac = get_interface_mac($realhwif);
4273
	$vendor_mac = get_interface_vendor_mac($realhwif);
4274

    
4275
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
4276
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
4277

    
4278
		interface_set_macaddr($realhwif, $mac_addr);
4279
	} else {
4280
		/*
4281
		 * this is not a valid mac address.  generate a
4282
		 * temporary mac address so the machine can get online.
4283
		 */
4284
		echo gettext("Generating new MAC address.");
4285
		$random_mac = generate_random_mac_address();
4286
		interface_set_macaddr($realhwif, $random_mac);
4287
		$config['interfaces'][$mac_if]['spoofmac'] = $random_mac;
4288
		write_config(sprintf(gettext('The invalid MAC address ' .
4289
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
4290
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
4291
		file_notice("MAC Address altered", sprintf(gettext('The ' .
4292
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
4293
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
4294
		    $random_mac), "Interfaces");
4295
	}
4296

    
4297
	/* media */
4298
	if ($wancfg['media'] || $wancfg['mediaopt']) {
4299
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
4300
		if ($wancfg['media']) {
4301
			$cmd .= " media " . escapeshellarg($wancfg['media']);
4302
		}
4303
		if ($wancfg['mediaopt']) {
4304
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
4305
		}
4306
		mwexec($cmd);
4307
	}
4308

    
4309
	/* Apply hw offloading policies as configured */
4310
	enable_hardware_offloading($interface);
4311

    
4312
	/* invalidate interface/ip/sn cache */
4313
	get_interface_arr(true);
4314
	unset($interface_ip_arr_cache[$realif]);
4315
	unset($interface_sn_arr_cache[$realif]);
4316
	unset($interface_ipv6_arr_cache[$realif]);
4317
	unset($interface_snv6_arr_cache[$realif]);
4318

    
4319
	$tunnelif = substr($realif, 0, 3);
4320

    
4321
	$mtuif = $realif;
4322
	$mtuhwif = $realhwif;
4323

    
4324
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
4325
	if (interface_isppp_type($interface)) {
4326
		$mtuif = $realhwif;
4327
		$mtuhwif_array = get_parent_interface($mtuif);
4328
		$mtuhwif = $mtuhwif_array[0];
4329
	}
4330

    
4331
	$wantedmtu = 0;
4332
	if (is_array($config['interfaces'])) {
4333
		foreach ($config['interfaces'] as $tmpinterface) {
4334
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
4335
				$wantedmtu = $tmpinterface['mtu'];
4336
				break;
4337
			}
4338
		}
4339
	}
4340

    
4341
	/* MTU is not specified for interface, try the pppoe settings. */
4342
	if ($wantedmtu == 0) {
4343
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
4344
	}
4345
	if (($wantedmtu == 0) && (interface_is_vlan($mtuif) != NULL) && interface_isppp_type($interface)) {
4346
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
4347
	}
4348
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gre')) {
4349
		/* set MTU to 1400 for GRE over IPsec */
4350
		if (is_greipsec($mtuif)) {
4351
			$wantedmtu = 1400;
4352
		} else {
4353
			$wantedmtu = 1476;
4354
		}
4355
	}
4356
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gif')) {
4357
		$wantedmtu = 1280;
4358
	}
4359
	/* Default MTU for WireGuard is 1420
4360
	 * https://redmine.pfsense.org/issues/11291 */
4361
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'wg')) {
4362
		$wantedmtu = 1420;
4363
	}
4364

    
4365
	/* Set the MTU to 1500 if no explicit MTU configured. */
4366
	if ($wantedmtu == 0) {
4367
		$wantedmtu = 1500; /* Default */
4368
	}
4369

    
4370
	if (interface_is_vlan($mtuif) != NULL) {
4371
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4372
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
4373
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
4374
			if ($wancfg['mtu'] > $parentmtu) {
4375
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4376
			}
4377
		}
4378

    
4379
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4380

    
4381
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4382
			$configuredmtu = $parentmtu;
4383
		if ($configuredmtu != 0)
4384
			$mtu = $configuredmtu;
4385
		else
4386
			$mtu = $wantedmtu;
4387

    
4388
		/* Set the parent MTU. */
4389
		if (get_interface_mtu($mtuhwif) < $mtu)
4390
			set_interface_mtu($mtuhwif, $mtu);
4391
		/* Set the VLAN MTU. */
4392
		if (get_interface_mtu($mtuif) != $mtu)
4393
			set_interface_mtu($mtuif, $mtu);
4394
	} elseif (substr($mtuif, 0, 4) == 'lagg') {
4395
		/* LAGG interface must be destroyed and re-created to change MTU */
4396
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4397
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
4398
				foreach ($config['laggs']['lagg'] as $lagg) {
4399
					if ($lagg['laggif'] == $mtuif) {
4400
						interface_lagg_configure($lagg);
4401
						break;
4402
					}
4403
				}
4404
			}
4405
		}
4406
	} else {
4407
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4408
			pfSense_interface_mtu($mtuif, $wantedmtu);
4409
			set_ipv6routes_mtu($mtuif, $wantedmtu);
4410
		}
4411
	}
4412
	/* XXX: What about gre/gif/.. ? */
4413

    
4414
	if (does_interface_exist($wancfg['if'])) {
4415
		interfaces_bring_up($wancfg['if']);
4416
	}
4417

    
4418
	switch ($wancfg['ipaddr']) {
4419
		case 'dhcp':
4420
			interface_dhcp_configure($interface);
4421
			break;
4422
		case 'pppoe':
4423
		case 'l2tp':
4424
		case 'pptp':
4425
		case 'ppp':
4426
			interface_ppps_configure($interface);
4427
			break;
4428
		default:
4429
			/* XXX: Kludge for now related to #3280 */
4430
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
4431
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
4432
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
4433
				}
4434
			}
4435
			break;
4436
	}
4437

    
4438
	switch ($wancfg['ipaddrv6']) {
4439
		case 'slaac':
4440
		case 'dhcp6':
4441
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
4442
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
4443
			// handles all non-PPP connections with 'dhcp6usev4iface' set
4444
			/* Remove the check file. Should not be there but just in case */
4445
			unlink_if_exists("/tmp/{$wanif}_dhcp6_complete");
4446
			log_error(gettext("calling interface_dhcpv6_configure."));
4447
			if ((($wancfg['ipaddrv6'] == 'dhcp6') && !isset($wancfg['dhcp6usev4iface'])) ||
4448
			    (($wancfg['ipaddrv6'] == 'slaac') && !isset($wancfg['slaacusev4iface'])) ||
4449
			    !interface_isppp_type($interface)) {
4450
				interface_dhcpv6_configure($interface, $wancfg);
4451
			}
4452
			break;
4453
		case '6rd':
4454
			interface_6rd_configure($interface, $wancfg);
4455
			break;
4456
		case '6to4':
4457
			interface_6to4_configure($interface, $wancfg);
4458
			break;
4459
		case 'track6':
4460
			interface_track6_configure($interface, $wancfg, $linkupevent);
4461
			break;
4462
		default:
4463
			/* XXX: Kludge for now related to #3280 */
4464
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
4465
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
4466
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
4467
					// FIXME: Add IPv6 Support to the pfSense module
4468
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
4469
				}
4470
			}
4471
			break;
4472
	}
4473

    
4474
	interface_netgraph_needed($interface);
4475

    
4476
	if (!platform_booting()) {
4477
		link_interface_to_vips($interface, "update");
4478

    
4479
		if ($tunnelif != 'gre') {
4480
			unset($gre);
4481
			$gre = link_interface_to_tunnelif($interface, 'gre');
4482
			if (!empty($gre)) {
4483
				array_walk($gre, 'interface_gre_configure');
4484
			}
4485
		}
4486

    
4487
		if ($tunnelif != 'gif') {
4488
			unset($gif);
4489
			$gif = link_interface_to_tunnelif($interface, 'gif');
4490
			if (!empty($gif)) {
4491
				array_walk($gif, 'interface_gif_configure');
4492
			}
4493
		}
4494

    
4495
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4496
			unset($bridgetmp);
4497
			$bridgetmp = link_interface_to_bridge($interface);
4498
			if (!empty($bridgetmp)) {
4499
				interface_bridge_add_member($bridgetmp, $realif);
4500
			}
4501
		}
4502

    
4503
		$grouptmp = link_interface_to_group($interface);
4504
		if (!empty($grouptmp)) {
4505
			array_walk($grouptmp, 'interface_group_add_member');
4506
		}
4507

    
4508
		if ($interface == "lan") {
4509
			/* make new hosts file */
4510
			system_hosts_generate();
4511
		}
4512

    
4513
		if ($reloadall == true) {
4514

    
4515
			/* reconfigure static routes (kernel may have deleted them) */
4516
			system_routing_configure($interface);
4517

    
4518
			/* reload ipsec tunnels */
4519
			send_event("service reload ipsecdns");
4520

    
4521
			if (isset($config['dnsmasq']['enable'])) {
4522
				services_dnsmasq_configure();
4523
			}
4524

    
4525
			if (isset($config['unbound']['enable'])) {
4526
				services_unbound_configure();
4527
			}
4528

    
4529
			/* update dyndns */
4530
			send_event("service reload dyndns {$interface}");
4531

    
4532
			/* reload captive portal */
4533
			if (!function_exists('captiveportal_init_rules_byinterface')) {
4534
				require_once('captiveportal.inc');
4535
			}
4536
			captiveportal_init_rules_byinterface($interface);
4537
		}
4538
	}
4539

    
4540
	if (!empty($wancfg['descr'])) {
4541
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4542
	};
4543

    
4544
	interfaces_staticarp_configure($interface);
4545
	return 0;
4546
}
4547

    
4548
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4549
	global $config, $g;
4550

    
4551
	if (!is_array($wancfg)) {
4552
		return;
4553
	}
4554

    
4555
	if (!isset($wancfg['enable'])) {
4556
		return;
4557
	}
4558

    
4559
	/* If the interface is not configured via another, exit */
4560
	if (empty($wancfg['track6-interface'])) {
4561
		return;
4562
	}
4563

    
4564
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4565
	$realif = get_real_interface($interface);
4566
	$linklocal = find_interface_ipv6_ll($realif, true);
4567
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4568
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4569
	}
4570

    
4571
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4572
	if (!isset($trackcfg['enable'])) {
4573
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4574
		return;
4575
	}
4576

    
4577
	switch ($trackcfg['ipaddrv6']) {
4578
		case "6to4":
4579
			if ($g['debug']) {
4580
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4581
			}
4582
			interface_track6_6to4_configure($interface, $wancfg);
4583
			break;
4584
		case "6rd":
4585
			if ($g['debug']) {
4586
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4587
			}
4588
			interface_track6_6rd_configure($interface, $wancfg);
4589
			break;
4590
		case "dhcp6":
4591
			if ($linkupevent == true) {
4592
				/*
4593
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4594
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4595
				 *
4596
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4597
				 */
4598
				$parentrealif = get_real_interface($wancfg['track6-interface']);
4599
				$pidv6 = find_dhcp6c_process($parentrealif);
4600
				if ($pidv6) {
4601
					posix_kill($pidv6, SIGHUP);
4602
				}
4603
			}
4604
			break;
4605
	}
4606

    
4607
	if ($linkupevent == false && !platform_booting()) {
4608
		if (!function_exists('services_dhcpd_configure')) {
4609
			require_once("services.inc");
4610
		}
4611

    
4612
		/* restart dns servers (defering dhcpd reload) */
4613
		if (isset($config['unbound']['enable'])) {
4614
			services_unbound_configure(false);
4615
		}
4616
		if (isset($config['dnsmasq']['enable'])) {
4617
			services_dnsmasq_configure(false);
4618
		}
4619

    
4620
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4621
		services_dhcpd_configure("inet6");
4622
	}
4623

    
4624
	return 0;
4625
}
4626

    
4627
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4628
	global $config, $g;
4629
	global $interface_ipv6_arr_cache;
4630
	global $interface_snv6_arr_cache;
4631

    
4632
	if (!is_array($lancfg)) {
4633
		return;
4634
	}
4635

    
4636
	/* If the interface is not configured via another, exit */
4637
	if (empty($lancfg['track6-interface'])) {
4638
		return;
4639
	}
4640

    
4641
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4642
	if (empty($wancfg)) {
4643
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4644
		return;
4645
	}
4646

    
4647
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4648
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4649
		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']));
4650
		return;
4651
	}
4652
	$hexwanv4 = return_hex_ipv4($ip4address);
4653

    
4654
	/* create the long prefix notation for math, save the prefix length */
4655
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4656
	$rd6prefixlen = $rd6prefix[1];
4657
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4658

    
4659
	/* binary presentation of the prefix for all 128 bits. */
4660
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4661

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

    
4667
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4668
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4669
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4670
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4671
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4672
	/* fill the rest out with zeros */
4673
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4674

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

    
4678
	$lanif = get_real_interface($interface);
4679
	$oip = find_interface_ipv6($lanif);
4680
	if (is_ipaddrv6($oip)) {
4681
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4682
	}
4683
	unset($interface_ipv6_arr_cache[$lanif]);
4684
	unset($interface_snv6_arr_cache[$lanif]);
4685
	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));
4686
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4687

    
4688
	return 0;
4689
}
4690

    
4691
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4692
	global $config, $g;
4693
	global $interface_ipv6_arr_cache;
4694
	global $interface_snv6_arr_cache;
4695

    
4696
	if (!is_array($lancfg)) {
4697
		return;
4698
	}
4699

    
4700
	/* If the interface is not configured via another, exit */
4701
	if (empty($lancfg['track6-interface'])) {
4702
		return;
4703
	}
4704

    
4705
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4706
	if (empty($wancfg)) {
4707
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4708
		return;
4709
	}
4710

    
4711
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4712
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4713
		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']));
4714
		return;
4715
	}
4716
	$hexwanv4 = return_hex_ipv4($ip4address);
4717

    
4718
	/* create the long prefix notation for math, save the prefix length */
4719
	$sixto4prefix = "2002::";
4720
	$sixto4prefixlen = 16;
4721
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4722

    
4723
	/* binary presentation of the prefix for all 128 bits. */
4724
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4725

    
4726
	/* just save the left prefix length bits */
4727
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4728
	/* add the v4 address */
4729
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4730
	/* add the custom prefix id */
4731
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4732
	/* fill the rest out with zeros */
4733
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4734

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

    
4738
	$lanif = get_real_interface($interface);
4739
	$oip = find_interface_ipv6($lanif);
4740
	if (is_ipaddrv6($oip)) {
4741
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4742
	}
4743
	unset($interface_ipv6_arr_cache[$lanif]);
4744
	unset($interface_snv6_arr_cache[$lanif]);
4745
	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));
4746
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4747

    
4748
	return 0;
4749
}
4750

    
4751
function interface_6rd_configure($interface = "wan", $wancfg) {
4752
	global $config, $g;
4753

    
4754
	/* because this is a tunnel interface we can only function
4755
	 *	with a public IPv4 address on the interface */
4756

    
4757
	if (!is_array($wancfg)) {
4758
		return;
4759
	}
4760

    
4761
	if (!is_module_loaded('if_stf.ko')) {
4762
		mwexec('/sbin/kldload if_stf.ko');
4763
	}
4764

    
4765
	$wanif = get_real_interface($interface);
4766
	$ip4address = find_interface_ip($wanif);
4767
	if (!is_ipaddrv4($ip4address)) {
4768
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4769
		return false;
4770
	}
4771
	$hexwanv4 = return_hex_ipv4($ip4address);
4772

    
4773
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4774
		$wancfg['prefix-6rd-v4plen'] = 0;
4775
	}
4776

    
4777
	/* create the long prefix notation for math, save the prefix length */
4778
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4779
	$rd6prefixlen = $rd6prefix[1];
4780
	$brgw = explode('.', $wancfg['gateway-6rd']);
4781
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4782
	$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);
4783
	if (strlen($rd6brgw) < 128) {
4784
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4785
	}
4786
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4787
	unset($brgw);
4788
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4789

    
4790
	/* binary presentation of the prefix for all 128 bits. */
4791
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4792

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

    
4800
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4801
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4802

    
4803

    
4804
	/* XXX: need to extend to support variable prefix size for v4 */
4805
	$stfiface = "{$interface}_stf";
4806
	if (does_interface_exist($stfiface)) {
4807
		pfSense_interface_destroy($stfiface);
4808
	}
4809
	$tmpstfiface = pfSense_interface_create2("stf");
4810
	pfSense_interface_rename($tmpstfiface, $stfiface);
4811
	pfSense_interface_flags($stfiface, IFF_LINK2);
4812
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4813
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4814
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4815
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4816
	}
4817
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4818
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4819
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4820
	} elseif ($parentmtu > 1300) {
4821
		set_interface_mtu($stfiface, $parentmtu - 20);
4822
	}
4823
	if ($g['debug']) {
4824
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4825
	}
4826

    
4827
	/* write out a default router file */
4828
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4829
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4830

    
4831
	$ip4gateway = get_interface_gateway($interface);
4832
	if (is_ipaddrv4($ip4gateway)) {
4833
		route_add_or_change($wancfg['gateway-6rd'], $ip4gateway);
4834
	}
4835

    
4836
	/* configure dependent interfaces */
4837
	if (!platform_booting()) {
4838
		link_interface_to_track6($interface, "update");
4839
	}
4840

    
4841
	return 0;
4842
}
4843

    
4844
function interface_6to4_configure($interface = "wan", $wancfg) {
4845
	global $config, $g;
4846

    
4847
	/* because this is a tunnel interface we can only function
4848
	 *	with a public IPv4 address on the interface */
4849

    
4850
	if (!is_array($wancfg)) {
4851
		return;
4852
	}
4853

    
4854
	$wanif = get_real_interface($interface);
4855
	$ip4address = find_interface_ip($wanif);
4856
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4857
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4858
		return false;
4859
	}
4860

    
4861
	/* create the long prefix notation for math, save the prefix length */
4862
	$stfprefixlen = 16;
4863
	$stfprefix = Net_IPv6::uncompress("2002::");
4864
	$stfarr = explode(":", $stfprefix);
4865
	$v4prefixlen = "0";
4866

    
4867
	/* we need the hex form of the interface IPv4 address */
4868
	$ip4arr = explode(".", $ip4address);
4869
	$hexwanv4 = "";
4870
	foreach ($ip4arr as $octet) {
4871
		$hexwanv4 .= sprintf("%02x", $octet);
4872
	}
4873

    
4874
	/* we need the hex form of the broker IPv4 address */
4875
	$ip4arr = explode(".", "192.88.99.1");
4876
	$hexbrv4 = "";
4877
	foreach ($ip4arr as $octet) {
4878
		$hexbrv4 .= sprintf("%02x", $octet);
4879
	}
4880

    
4881
	/* binary presentation of the prefix for all 128 bits. */
4882
	$stfprefixbin = "";
4883
	foreach ($stfarr as $element) {
4884
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4885
	}
4886
	/* just save the left prefix length bits */
4887
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4888

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

    
4893
	/* for the local subnet too. */
4894
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4895
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4896

    
4897
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4898
	$stfbrarr = array();
4899
	$stfbrbinarr = array();
4900
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4901
	foreach ($stfbrbinarr as $bin) {
4902
		$stfbrarr[] = dechex(bindec($bin));
4903
	}
4904
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4905

    
4906
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4907
	$stflanarr = array();
4908
	$stflanbinarr = array();
4909
	$stflanbinarr = str_split($stflanbin, 16);
4910
	foreach ($stflanbinarr as $bin) {
4911
		$stflanarr[] = dechex(bindec($bin));
4912
	}
4913
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4914
	$stflanarr[7] = 1;
4915
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4916

    
4917
	/* setup the stf interface */
4918
	if (!is_module_loaded("if_stf")) {
4919
		mwexec("/sbin/kldload if_stf.ko");
4920
	}
4921
	$stfiface = "{$interface}_stf";
4922
	if (does_interface_exist($stfiface)) {
4923
		pfSense_interface_destroy($stfiface);
4924
	}
4925
	$tmpstfiface = pfSense_interface_create2("stf");
4926
	pfSense_interface_rename($tmpstfiface, $stfiface);
4927
	pfSense_interface_flags($stfiface, IFF_LINK2);
4928
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4929

    
4930
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4931
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4932
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4933
	} elseif ($parentmtu > 1300) {
4934
		set_interface_mtu($stfiface, $parentmtu - 20);
4935
	}
4936
	if ($g['debug']) {
4937
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4938
	}
4939

    
4940
	/* write out a default router file */
4941
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4942
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4943

    
4944
	$ip4gateway = get_interface_gateway($interface);
4945
	if (is_ipaddrv4($ip4gateway)) {
4946
		route_add_or_change("192.88.99.1", $ip4gateway);
4947
	}
4948

    
4949
	if (!platform_booting()) {
4950
		link_interface_to_track6($interface, "update");
4951
	}
4952

    
4953
	return 0;
4954
}
4955

    
4956
function interface_dhcpv6_configure($interface = "wan", $wancfg) {
4957
	global $config, $g;
4958

    
4959
	if (!is_array($wancfg)) {
4960
		return;
4961
	}
4962

    
4963
	$wanif = get_real_interface($interface, "inet6");
4964
	$dhcp6cconf = "";
4965

    
4966
	if (!empty($config['system']['global-v6duid'])) {
4967
		// Write the DUID file
4968
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4969
		    log_error(gettext("Failed to write user DUID file!"));
4970
		}
4971
	}
4972

    
4973
	/* accept router advertisements for this interface                 */
4974
	/* Moved to early in the function as sometimes interface not ready */
4975
	/* RTSOLD fails as interface does not accept .....                 */
4976

    
4977
	log_error("Accept router advertisements on interface {$wanif} ");
4978
	mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4979

    
4980
	if ($wancfg['adv_dhcp6_config_file_override']) {
4981
		// DHCP6 Config File Override
4982
		$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4983
	} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4984
		// DHCP6 Config File Advanced
4985
		$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4986
	} else {
4987
		// DHCP6 Config File Basic
4988
		$dhcp6cconf .= "interface {$wanif} {\n";
4989

    
4990
		/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4991
		if ($wancfg['ipaddrv6'] == "slaac") {
4992
			$dhcp6cconf .= "\tinformation-only;\n";
4993
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
4994
			$dhcp6cconf .= "\trequest domain-name;\n";
4995
			$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4996
			$dhcp6cconf .= "};\n";
4997
		} else {
4998
			$trackiflist = array();
4999
			$iflist = link_interface_to_track6($interface);
5000
			foreach ($iflist as $ifname => $ifcfg) {
5001
				if (is_numeric($ifcfg['track6-prefix-id'])) {
5002
					$trackiflist[$ifname] = $ifcfg;
5003
				}
5004
			}
5005

    
5006
			/* skip address request if this is set */
5007
			if (!isset($wancfg['dhcp6prefixonly'])) {
5008
				$dhcp6cconf .= "\tsend ia-na 0;\t# request stateful address\n";
5009
			}
5010
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
5011
				$dhcp6cconf .= "\tsend ia-pd 0;\t# request prefix delegation\n";
5012
			}
5013

    
5014
			$dhcp6cconf .= "\trequest domain-name-servers;\n";
5015
			$dhcp6cconf .= "\trequest domain-name;\n";
5016

    
5017
			/*
5018
			 * dhcp6c will run different scripts depending on
5019
			 * whether dhcpwithoutra is set or unset.
5020
			 */
5021
			if (isset($wancfg['dhcp6withoutra'])) {
5022
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
5023
			} else {
5024
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
5025
			}
5026
			$dhcp6cconf .= "};\n";
5027

    
5028
			if (!isset($wancfg['dhcp6prefixonly'])) {
5029
				$dhcp6cconf .= "id-assoc na 0 { };\n";
5030
			}
5031

    
5032
			if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
5033
				/* Setup the prefix delegation */
5034
				$dhcp6cconf .= "id-assoc pd 0 {\n";
5035
				$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
5036
				if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
5037
					$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
5038
				}
5039
				foreach ($trackiflist as $friendly => $ifcfg) {
5040
					if ($g['debug']) {
5041
						log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
5042
					}
5043
					$realif = get_real_interface($friendly);
5044
					$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
5045
					$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
5046
					$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
5047
					$dhcp6cconf .= "\t};\n";
5048
				}
5049
				unset($preflen, $iflist, $ifcfg, $ifname);
5050
				$dhcp6cconf .= "};\n";
5051
			}
5052
			unset($trackiflist);
5053
		}
5054
	}
5055

    
5056
	$debugOption = isset($wancfg['dhcp6debug']) ? "-D" : "-d";
5057
	$noreleaseOption = isset($wancfg['dhcp6norelease']) ? "-n" : "";
5058

    
5059
	/* wide-dhcp6c works for now. */
5060
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}.conf", $dhcp6cconf)) {
5061
		printf("Error: cannot open dhcp6c_{$interface}.conf in interface_dhcpv6_configure() for writing.\n");
5062
		unset($dhcp6cconf);
5063
		return 1;
5064
	}
5065
	unset($dhcp6cconf);
5066

    
5067
	/*************** Script Debug Logging ***************************
5068
	Both dhcp6 scripts now have a logging message built in.
5069
	These logging messages ONLY appear if dhcp6c debug logging is set.
5070
	The logging messages appear in the dhcp section of the logs,
5071
	not in system.
5072

    
5073
	These scripts now also take advantage of the REASON= env vars
5074
	supplied by dhcp6c.
5075
	****************************************************************/
5076

    
5077
	/* Script create for dhcp6withoutRA mode */
5078
	/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
5079
	$dhcp6cscriptwithoutra = "#!/bin/sh\n";
5080
	$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
5081
	$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
5082
	$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
5083
	$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
5084
	// Need to pass params to  the final script
5085
	$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
5086
	$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
5087
	$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
5088
	$dhcp6cscriptwithoutra .= "case \$REASON in\n";
5089
	$dhcp6cscriptwithoutra .= "REQUEST)\n";
5090
	$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
5091
	$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
5092
	if ($debugOption == '-D') {
5093
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rtsold\"\n";
5094
	}
5095
	$dhcp6cscriptwithoutra .= ";;\n";
5096
	$dhcp6cscriptwithoutra .= "REBIND)\n";
5097
	if ($debugOption == '-D') {
5098
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
5099
	}
5100
	$dhcp6cscriptwithoutra .= ";;\n";
5101
	if (isset($wancfg['dhcp6norelease'])) {
5102
		$dhcp6cscriptwithoutra .= "EXIT)\n";
5103
	} else {
5104
		$dhcp6cscriptwithoutra .= "RELEASE)\n";
5105
	}
5106
	if ($debugOption == '-D') {
5107
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
5108
	}
5109
	$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5110
	$dhcp6cscriptwithoutra .= ";;\n";
5111
	$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
5112
	if ($debugOption == '-D') {
5113
		$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5114
	}
5115
	$dhcp6cscriptwithoutra .= "esac\n";
5116
	if (!@file_put_contents(
5117
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
5118
	    $dhcp6cscriptwithoutra)) {
5119
		printf("Error: cannot open " .
5120
		    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
5121
		    "interface_dhcpv6_configure() for writing.\n");
5122
		unset($dhcp6cscriptwithoutra);
5123
		return 1;
5124
	}
5125

    
5126
	unset($dhcp6cscriptwithoutra);
5127
	@chmod(
5128
	    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
5129
	    0755);
5130

    
5131
	/*
5132
	 * Dual mode wan_dhcp6c script with variations depending on node
5133
	 * dhcp6 will run the wan ipv6 configure
5134
	 */
5135
	$dhcp6cscript  = "#!/bin/sh\n";
5136
	$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
5137
	if (!isset($wancfg['dhcp6withoutra'])) {
5138
		$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
5139
		$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
5140
		$dhcp6cscript .= "case \$REASON in\n";
5141
		$dhcp6cscript .= "REBIND)\n";
5142
		if ($debugOption == '-D') {
5143
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
5144
		}
5145
		$dhcp6cscript .= ";;\n";
5146
		$dhcp6cscript .= "REQUEST|";
5147
		if (isset($wancfg['dhcp6norelease'])) {
5148
			$dhcp6cscript .= "EXIT)\n";
5149
		} else {
5150
			$dhcp6cscript .= "RELEASE)\n";
5151
		}
5152
		if ($debugOption == '-D') {
5153
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c RELEASE, REQUEST or EXIT on {$wanif} running rc.newwanipv6\"\n";
5154
		}
5155
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5156
		$dhcp6cscript .= ";;\n";
5157
		$dhcp6cscript .= "RENEW|INFO)\n";
5158
		if ($debugOption == '-D') {
5159
			$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5160
		}
5161
		$dhcp6cscript .= "esac\n";
5162
	} else {
5163
		// Need to get the parameters from the dhcp6cwithoutRA run
5164
		$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
5165
		$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
5166
		$dhcp6cscript .= "/bin/sleep 1\n";
5167
		$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5168
	}
5169

    
5170
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5171
	if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
5172
		printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
5173
		unset($dhcp6cscript);
5174
		return 1;
5175
	}
5176
	unset($dhcp6cscript);
5177
	@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
5178

    
5179
	$rtsoldscript = <<<EOD
5180
#!/bin/sh
5181
# This shell script launches dhcp6c and configured gateways for this interface.
5182
if [ -n "\$2" ]; then
5183
	echo \$2 > {$g['tmp_path']}/{$wanif}_routerv6
5184
	echo \$2 > {$g['tmp_path']}/{$wanif}_defaultgwv6
5185
	/usr/bin/logger -t rtsold "Received RA specifying route \$2 for interface {$interface}({$wanif})"
5186
fi
5187

    
5188
EOD;
5189

    
5190
	/* non ipoe Process */
5191
	if (!isset($wancfg['dhcp6withoutra'])) {
5192
		/*
5193
		 * We only want this script to run once, and if it runs twice
5194
		 * then do not launch dhcp6c again, this only happens if
5195
		 * dhcpwithoutra is not set.
5196
		 *
5197
		 * Check for a lock file, trying to prevent multiple instances
5198
		 * of dhcp6c being launched
5199
		 */
5200
		$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_{$wanif}_lock ]; then\n";
5201
		/*
5202
		 * Create the lock file, trying to prevent multiple instances
5203
		 * of dhcp6c being launched
5204
		 */
5205
		$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_{$wanif}_lock\n";
5206
		$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid ]; then\n";
5207
		$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
5208
		$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c_{$wanif}.pid\n";
5209
		$rtsoldscript .= "\t\t/bin/sleep 1\n";
5210
		$rtsoldscript .= "\tfi\n";
5211
		$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
5212
		    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c_{$interface}.conf " .
5213
		    "-p {$g['varrun_path']}/dhcp6c_{$wanif}.pid {$wanif}\n";
5214
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interface {$interface}({$wanif})\"\n";
5215
		$rtsoldscript .= "else\n";
5216
		$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
5217
		$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c_{$wanif}.pid\")\n";
5218
		$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
5219
		$rtsoldscript .= "fi\n";
5220
	} else {
5221
		/*
5222
		 * The script needs to run in dhcp6withoutra mode as RA may
5223
		 * not have been received, or there can be a delay with
5224
		 * certain ISPs
5225
		 */
5226
		$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
5227
		$rtsoldscript .= "/bin/sleep 1\n";
5228
	}
5229
	/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5230
	if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
5231
		printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
5232
		unset($rtsoldscript);
5233
		return 1;
5234
	}
5235
	unset($rtsoldscript);
5236
	@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
5237

    
5238
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
5239
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
5240
		log_error("Killing running rtsold process");
5241
		sleep(2);
5242
	}
5243

    
5244
	if (isset($wancfg['dhcp6withoutra'])) {
5245
		/*
5246
		 * Start dhcp6c here if we don't want to wait for ra - calls
5247
		 * separate function
5248
		 *
5249
		 * In this mode dhcp6c launches rtsold via its script. RTSOLD
5250
		 * will then run the configure on receipt of the RA.
5251
		 *
5252
		 * Already started. interface_dhcpv6_configure() appears to get
5253
		 * called multiple times.
5254
		 *
5255
		 * Taking the interface down or releasing will kill the client.
5256
		 */
5257
		if (!file_exists("/tmp/dhcp6c_{$wanif}_lock"))
5258
		{
5259
			/*
5260
			 * If the interface is being brought up, wait for the
5261
			 * interface to configure accept RA before launching.
5262
			 * Otherwise it is not ready to accept and will fail.
5263
			 */
5264
			sleep(3);
5265
			run_dhcp6client_process($wanif,$interface,$wancfg);
5266
		}
5267
	} else {
5268
		/*
5269
		 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
5270
		 * ( it does not background, it exits! ) It will launch dhcp6c
5271
		 * if dhcpwihtoutra is not set
5272
		 */
5273
		log_error("Starting rtsold process");
5274
		sleep(2);
5275
		mwexec("/usr/sbin/rtsold -1 " .
5276
		    "-p {$g['varrun_path']}/rtsold_{$wanif}.pid " .
5277
		    "-M {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
5278
		    "-O {$g['varetc_path']}/rtsold_{$wanif}_script.sh " .
5279
		    $wanif);
5280
	}
5281
	/*
5282
	 * NOTE: will be called from rtsold invoked script
5283
	 * link_interface_to_track6($interface, "update");
5284
	 */
5285

    
5286
	return 0;
5287
}
5288

    
5289
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5290
	global $g;
5291

    
5292
	$send_options = "";
5293
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
5294
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
5295
		foreach ($options as $option) {
5296
			$send_options .= "\tsend " . trim($option) . ";\n";
5297
		}
5298
	}
5299

    
5300
	$request_options = "";
5301
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5302
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5303
		foreach ($options as $option) {
5304
			$request_options .= "\trequest " . trim($option) . ";\n";
5305
		}
5306
	}
5307

    
5308
	$information_only = "";
5309
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5310
		$information_only = "\tinformation-only;\n";
5311
	}
5312

    
5313
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5314
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5315
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5316
	}
5317

    
5318
	$interface_statement  = "interface";
5319
	$interface_statement .= " {$wanif}";
5320
	$interface_statement .= " {\n";
5321
	$interface_statement .= "$send_options";
5322
	$interface_statement .= "$request_options";
5323
	$interface_statement .= "$information_only";
5324
	$interface_statement .= "$script";
5325
	$interface_statement .= "};\n";
5326

    
5327
	$id_assoc_statement_address = "";
5328
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5329
		$id_assoc_statement_address .= "id-assoc";
5330
		$id_assoc_statement_address .= " na";
5331
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5332
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5333
		}
5334
		$id_assoc_statement_address .= " { ";
5335

    
5336
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5337
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5338
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5339
			$id_assoc_statement_address .= "\n\taddress";
5340
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5341
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5342
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5343
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5344
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5345
			}
5346
			$id_assoc_statement_address .= ";\n";
5347
		}
5348

    
5349
		$id_assoc_statement_address .= "};\n";
5350
	}
5351

    
5352
	$id_assoc_statement_prefix = "";
5353
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5354
		$id_assoc_statement_prefix .= "id-assoc";
5355
		$id_assoc_statement_prefix .= " pd";
5356
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5357
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5358
		}
5359
		$id_assoc_statement_prefix .= " { ";
5360

    
5361
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5362
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5363
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5364
			$id_assoc_statement_prefix .= "\n\tprefix";
5365
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5366
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5367
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5368
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5369
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5370
			}
5371
			$id_assoc_statement_prefix .= ";";
5372
		}
5373

    
5374
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
5375
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
5376
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
5377
			$id_assoc_statement_prefix .= " {$realif}";
5378
			$id_assoc_statement_prefix .= " {\n";
5379
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
5380
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
5381
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
5382
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
5383
			}
5384
			$id_assoc_statement_prefix .= "\t};";
5385
		}
5386

    
5387
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5388
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5389
			$id_assoc_statement_prefix .= "\n";
5390
		}
5391

    
5392
		$id_assoc_statement_prefix .= "};\n";
5393
	}
5394

    
5395
	$authentication_statement = "";
5396
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
5397
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
5398
		$authentication_statement .= "authentication";
5399
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
5400
		$authentication_statement .= " {\n";
5401
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
5402
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
5403
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
5404
		}
5405
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
5406
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
5407
		}
5408
		$authentication_statement .= "};\n";
5409
	}
5410

    
5411
	$key_info_statement = "";
5412
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5413
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5414
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5415
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5416
		$key_info_statement .= "keyinfo";
5417
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5418
		$key_info_statement .= " {\n";
5419
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5420
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5421
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5422
		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'])) {
5423
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5424
		}
5425
		$key_info_statement .= "};\n";
5426
	}
5427

    
5428
	$dhcp6cconf  = $interface_statement;
5429
	$dhcp6cconf .= $id_assoc_statement_address;
5430
	$dhcp6cconf .= $id_assoc_statement_prefix;
5431
	$dhcp6cconf .= $authentication_statement;
5432
	$dhcp6cconf .= $key_info_statement;
5433

    
5434
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5435

    
5436
	return $dhcp6cconf;
5437
}
5438

    
5439

    
5440
function DHCP6_Config_File_Override($wancfg, $wanif) {
5441

    
5442
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5443

    
5444
	if ($dhcp6cconf === false) {
5445
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5446
		return '';
5447
	} else {
5448
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5449
	}
5450
}
5451

    
5452

    
5453
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5454

    
5455
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5456

    
5457
	return $dhcp6cconf;
5458
}
5459

    
5460

    
5461
function interface_dhcp_configure($interface = "wan") {
5462
	global $config, $g, $vlanprio_values;
5463

    
5464
	$ifcfg = $config['interfaces'][$interface];
5465
	if (empty($ifcfg)) {
5466
		$ifcfg = array();
5467
	}
5468

    
5469
	$dhclientconf_vlantag = "";
5470
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5471
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5472
	}
5473

    
5474
	/* generate dhclient_wan.conf */
5475
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5476
	if (!$fd) {
5477
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5478
		return 1;
5479
	}
5480

    
5481
	if ($ifcfg['dhcphostname']) {
5482
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5483
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5484
	} else {
5485
		$dhclientconf_hostname = "";
5486
	}
5487

    
5488
	$realif = get_real_interface($interface);
5489
	if (empty($realif)) {
5490
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5491
		return 0;
5492
	}
5493
	$dhclientconf = "";
5494

    
5495
	$dhclientconf .= <<<EOD
5496
interface "{$realif}" {
5497
	supersede interface-mtu 0;
5498
	timeout 60;
5499
	retry 15;
5500
	select-timeout 0;
5501
	initial-interval 1;
5502
	{$dhclientconf_vlantag}
5503
	{$dhclientconf_hostname}
5504
	script "/usr/local/sbin/pfSense-dhclient-script";
5505
EOD;
5506

    
5507
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5508
		$dhclientconf .= <<<EOD
5509

    
5510
	reject {$ifcfg['dhcprejectfrom']};
5511
EOD;
5512
	}
5513
	$dhclientconf .= <<<EOD
5514

    
5515
}
5516

    
5517
EOD;
5518

    
5519
	// DHCP Config File Advanced
5520
	if ($ifcfg['adv_dhcp_config_advanced']) {
5521
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5522
	}
5523

    
5524
	if (is_ipaddr($ifcfg['alias-address'])) {
5525
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5526
		$dhclientconf .= <<<EOD
5527
alias {
5528
	interface "{$realif}";
5529
	fixed-address {$ifcfg['alias-address']};
5530
	option subnet-mask {$subnetmask};
5531
}
5532

    
5533
EOD;
5534
	}
5535

    
5536
	// DHCP Config File Override
5537
	if ($ifcfg['adv_dhcp_config_file_override']) {
5538
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5539
	}
5540

    
5541
	fwrite($fd, $dhclientconf);
5542
	fclose($fd);
5543

    
5544
	/* bring wan interface up before starting dhclient */
5545
	if ($realif) {
5546
		interfaces_bring_up($realif);
5547
	}
5548

    
5549
	/* Make sure dhclient is not running */
5550
	kill_dhclient_process($realif);
5551

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

    
5555
	return 0;
5556
}
5557

    
5558
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5559

    
5560
	$hostname = "";
5561
	if ($ifcfg['dhcphostname'] != '') {
5562
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5563
	}
5564

    
5565
	/* DHCP Protocol Timings */
5566
	$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");
5567
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5568
		$pt_variable = "{$Protocol_Timing}";
5569
		${$pt_variable} = "";
5570
		if ($ifcfg[$Protocol_Timing] != "") {
5571
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5572
		}
5573
	}
5574

    
5575
	$send_options = "";
5576
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5577
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5578
		foreach ($options as $option) {
5579
			$send_options .= "\tsend " . trim($option) . ";\n";
5580
		}
5581
	}
5582

    
5583
	$request_options = "";
5584
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5585
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5586
	}
5587

    
5588
	$required_options = "";
5589
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5590
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5591
	}
5592

    
5593
	$option_modifiers = "";
5594
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5595
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5596
		foreach ($modifiers as $modifier) {
5597
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5598
		}
5599
	}
5600

    
5601
	$dhclientconf  = "interface \"{$realif}\" {\n";
5602
	$dhclientconf .= "\n";
5603
	$dhclientconf .= "\tsupersede interface-mtu 0;\n";
5604
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5605
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5606
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5607
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5608
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5609
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5610
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5611
	$dhclientconf .= "\n";
5612
	$dhclientconf .= "# DHCP Protocol Options\n";
5613
	$dhclientconf .= "{$hostname}";
5614
	$dhclientconf .= "{$send_options}";
5615
	$dhclientconf .= "{$request_options}";
5616
	$dhclientconf .= "{$required_options}";
5617
	$dhclientconf .= "{$option_modifiers}";
5618
	$dhclientconf .= "\n";
5619
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5620
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5621
	}
5622
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5623
	$dhclientconf .= "}\n";
5624

    
5625
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5626

    
5627
	return $dhclientconf;
5628
}
5629

    
5630
function DHCP_Config_Option_Split($option_string) {
5631
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5632
	return $matches ? $matches[0] : [];
5633
}
5634

    
5635
function DHCP_Config_File_Override($ifcfg, $realif) {
5636

    
5637
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5638

    
5639
	if ($dhclientconf === false) {
5640
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5641
		return '';
5642
	} else {
5643
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5644
	}
5645
}
5646

    
5647

    
5648
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5649

    
5650
	/* Apply Interface Substitutions */
5651
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5652

    
5653
	/* Apply Hostname Substitutions */
5654
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5655

    
5656
	/* Arrays of MAC Address Types, Cases, Delimiters */
5657
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5658
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5659
	$various_mac_cases      = array("U", "L");
5660
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5661

    
5662
	/* Apply MAC Address Substitutions */
5663
	foreach ($various_mac_types as $various_mac_type) {
5664
		foreach ($various_mac_cases as $various_mac_case) {
5665
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5666

    
5667
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5668
				if ($res !== false) {
5669

    
5670
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5671
					if ("$various_mac_case" == "U") {
5672
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5673
					}
5674
					if ("$various_mac_case" == "L") {
5675
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5676
					}
5677

    
5678
					if ("$various_mac_type" == "mac_addr_hex") {
5679
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5680
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5681
						$dhcpclientconf_mac_hex = "";
5682
						$delimiter = "";
5683
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5684
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5685
							$delimiter = ":";
5686
						}
5687
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5688
					}
5689

    
5690
					/* MAC Address Delimiter Substitutions */
5691
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5692

    
5693
					/* Apply MAC Address Substitutions */
5694
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5695
				}
5696
			}
5697
		}
5698
	}
5699

    
5700
	return $dhclientconf;
5701
}
5702

    
5703
function interfaces_group_setup() {
5704
	global $config;
5705

    
5706
	if (!isset($config['ifgroups']['ifgroupentry']) ||
5707
	    !is_array($config['ifgroups']['ifgroupentry'])) {
5708
		return;
5709
	}
5710

    
5711
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5712
		interface_group_setup($groupar);
5713
	}
5714

    
5715
	return;
5716
}
5717

    
5718
function interface_group_setup(&$groupname /* The parameter is an array */) {
5719
	global $config;
5720

    
5721
	if (!is_array($groupname)) {
5722
		return;
5723
	}
5724
	$members = explode(" ", $groupname['members']);
5725
	foreach ($members as $ifs) {
5726
		$realif = get_real_interface($ifs);
5727
		if ($realif && does_interface_exist($realif)) {
5728
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5729
		}
5730
	}
5731

    
5732
	return;
5733
}
5734

    
5735
function is_interface_group($if) {
5736
	global $config;
5737

    
5738
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5739
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5740
			if ($groupentry['ifname'] === $if) {
5741
				return true;
5742
			}
5743
		}
5744
	}
5745

    
5746
	return false;
5747
}
5748

    
5749
function interface_group_add_member($interface, $groupname) {
5750
	$interface = get_real_interface($interface);
5751
	if (does_interface_exist($interface)) {
5752
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5753
	}
5754
}
5755

    
5756
/* COMPAT Function */
5757
function convert_friendly_interface_to_real_interface_name($interface) {
5758
	return get_real_interface($interface);
5759
}
5760

    
5761
/* COMPAT Function */
5762
function get_real_wan_interface($interface = "wan") {
5763
	return get_real_interface($interface);
5764
}
5765

    
5766
/* COMPAT Function */
5767
function get_current_wan_address($interface = "wan") {
5768
	return get_interface_ip($interface);
5769
}
5770

    
5771
/*
5772
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5773
 */
5774
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5775
	global $config;
5776

    
5777
	/* XXX: For speed reasons reference directly the interface array */
5778
	init_config_arr(array('interfaces'));
5779
	$ifdescrs = &$config['interfaces'];
5780
	//$ifdescrs = get_configured_interface_list(true);
5781

    
5782
	foreach ($ifdescrs as $if => $ifname) {
5783
		if ($if == $interface || $ifname['if'] == $interface) {
5784
			return $if;
5785
		}
5786

    
5787
		if (get_real_interface($if) == $interface) {
5788
			return $if;
5789
		}
5790

    
5791
		if ($checkparent == false) {
5792
			continue;
5793
		}
5794

    
5795
		$int = get_parent_interface($if, true);
5796
		if (is_array($int)) {
5797
			foreach ($int as $iface) {
5798
				if ($iface == $interface) {
5799
					return $if;
5800
				}
5801
			}
5802
		}
5803
	}
5804

    
5805
	if ($interface == "enc0") {
5806
		return 'IPsec';
5807
	}
5808
}
5809

    
5810
/* attempt to resolve interface to friendly descr */
5811
function convert_friendly_interface_to_friendly_descr($interface) {
5812
	global $config;
5813

    
5814
	switch ($interface) {
5815
		case "l2tp":
5816
			$ifdesc = "L2TP";
5817
			break;
5818
		case "pptp":
5819
			$ifdesc = "PPTP";
5820
			break;
5821
		case "pppoe":
5822
			$ifdesc = "PPPoE";
5823
			break;
5824
		case "openvpn":
5825
			$ifdesc = "OpenVPN";
5826
			break;
5827
		case "wireguard":
5828
			$ifdesc = "WireGuard";
5829
			break;
5830
		case "lo0":
5831
			$ifdesc = "Loopback";
5832
			break;
5833
		case "enc0":
5834
		case "ipsec":
5835
		case "IPsec":
5836
			$ifdesc = "IPsec";
5837
			break;
5838
		default:
5839
			if (isset($config['interfaces'][$interface])) {
5840
				if (empty($config['interfaces'][$interface]['descr'])) {
5841
					$ifdesc = strtoupper($interface);
5842
				} else {
5843
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5844
				}
5845
				break;
5846
			} elseif (substr($interface, 0, 4) == '_vip') {
5847
				if (is_array($config['virtualip']['vip'])) {
5848
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5849
						if ($vip['mode'] == "carp") {
5850
							if ($interface == "_vip{$vip['uniqid']}") {
5851
								$descr = $vip['subnet'];
5852
								$descr .= " (vhid {$vip['vhid']})";
5853
								if (!empty($vip['descr'])) {
5854
									$descr .= " - " .$vip['descr'];
5855
								}
5856
								return $descr;
5857
							}
5858
						}
5859
					}
5860
				}
5861
			} elseif (substr($interface, 0, 5) == '_lloc') {
5862
				return get_interface_linklocal($interface);
5863
			} else {
5864
				if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5865
					foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
5866
						if ($ifgen['ifname'] === $interface) {
5867
							return $ifgen['ifname'];
5868
						}
5869
					}
5870
				}
5871

    
5872
				/* if list */
5873
				$ifdescrs = get_configured_interface_with_descr(true);
5874
				foreach ($ifdescrs as $if => $ifname) {
5875
					if ($if == $interface || $ifname == $interface) {
5876
						return $ifname;
5877
					}
5878
				}
5879
			}
5880
			break;
5881
	}
5882

    
5883
	return $ifdesc;
5884
}
5885

    
5886
function convert_real_interface_to_friendly_descr($interface) {
5887

    
5888
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5889

    
5890
	if (!empty($ifdesc)) {
5891
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5892
	}
5893

    
5894
	return $interface;
5895
}
5896

    
5897
/*
5898
 *  get_parent_interface($interface):
5899
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5900
 *				or virtual interface (i.e. vlan)
5901
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5902
 *			-- returns $interface passed in if $interface parent is not found
5903
 *			-- returns empty array if an invalid interface is passed
5904
 *	(Only handles ppps and vlans now.)
5905
 */
5906
function get_parent_interface($interface, $avoidrecurse = false) {
5907
	global $config;
5908

    
5909
	$parents = array();
5910
	//Check that we got a valid interface passed
5911
	$realif = get_real_interface($interface);
5912
	if ($realif == NULL) {
5913
		return $parents;
5914
	}
5915

    
5916
	// If we got a real interface, find it's friendly assigned name
5917
	if ($interface == $realif && $avoidrecurse == false) {
5918
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5919
	}
5920

    
5921
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5922
		$ifcfg = $config['interfaces'][$interface];
5923
		switch ($ifcfg['ipaddr']) {
5924
			case "ppp":
5925
			case "pppoe":
5926
			case "pptp":
5927
			case "l2tp":
5928
				if (empty($parents)) {
5929
					if (is_array($config['ppps']['ppp'])) {
5930
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5931
							if ($ifcfg['if'] == $ppp['if']) {
5932
								$ports = explode(',', $ppp['ports']);
5933
								foreach ($ports as $pid => $parent_if) {
5934
									$parents[$pid] = get_real_interface($parent_if);
5935
								}
5936
								break;
5937
							}
5938
						}
5939
					}
5940
				}
5941
				break;
5942
			case "dhcp":
5943
			case "static":
5944
			default:
5945
				// Handle _vlans
5946
				$vlan = interface_is_vlan($ifcfg['if']);
5947
				if ($vlan != NULL) {
5948
					$parents[0] = $vlan['if'];
5949
				}
5950
				break;
5951
		}
5952
	}
5953

    
5954
	if (empty($parents)) {
5955
		// Handle _vlans not assigned to an interface
5956
		$vlan = interface_is_vlan($realif);
5957
		if ($vlan != NULL) {
5958
			$parents[0] = $vlan['if'];
5959
		}
5960
	}
5961

    
5962
	if (empty($parents)) {
5963
		/* Handle LAGGs. */
5964
		$lagg = interface_is_type($realif, 'lagg');
5965
		if ($lagg != NULL && isset($lagg['members'])) {
5966
			$parents = explode(",", $lagg['members']);
5967
		}
5968
	}
5969

    
5970
	if (empty($parents)) {
5971
		$parents[0] = $realif;
5972
	}
5973

    
5974
	return $parents;
5975
}
5976

    
5977
/*
5978
 *  get_parent_physical_interface($interface):
5979
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5980
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5981
 */
5982
function get_parent_physical_interface($interface) {
5983
	global $config;
5984

    
5985
	$realif = get_parent_interface($interface);
5986

    
5987
	if (substr($realif[0], 0, 4) == "lagg") {
5988
		foreach ($config['laggs']['lagg'] as $lagg) {
5989
			if ($realif[0] == $lagg['laggif']) {
5990
				return explode(",", $lagg['members']);
5991
			}
5992
		}
5993
	} else {
5994
		return $realif;
5995
	}
5996
}
5997

    
5998
function interface_is_wireless_clone($wlif) {
5999
	if (!stristr($wlif, "_wlan")) {
6000
		return false;
6001
	} else {
6002
		return true;
6003
	}
6004
}
6005

    
6006
function interface_get_wireless_base($wlif) {
6007
	if (!stristr($wlif, "_wlan")) {
6008
		return $wlif;
6009
	} else {
6010
		return substr($wlif, 0, stripos($wlif, "_wlan"));
6011
	}
6012
}
6013

    
6014
function interface_get_wireless_clone($wlif) {
6015
	if (!stristr($wlif, "_wlan")) {
6016
		return $wlif . "_wlan0";
6017
	} else {
6018
		return $wlif;
6019
	}
6020
}
6021

    
6022
function interface_list_wireless() {
6023
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
6024

    
6025
	$result = array();
6026
	foreach ($portlist as $port) {
6027
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
6028
			continue;
6029
		}
6030

    
6031
		$desc = $port . " ( " . get_single_sysctl(
6032
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
6033

    
6034
		$result[] = array(
6035
		    "if" => $port,
6036
		    "descr" => $desc
6037
		);
6038
	}
6039

    
6040
	return $result;
6041
}
6042

    
6043
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = false) {
6044
	global $config, $g;
6045

    
6046
	$wanif = NULL;
6047

    
6048
	switch ($interface) {
6049
		case "l2tp":
6050
			$wanif = "l2tp";
6051
			break;
6052
		case "pptp":
6053
			$wanif = "pptp";
6054
			break;
6055
		case "pppoe":
6056
			$wanif = "pppoe";
6057
			break;
6058
		case "openvpn":
6059
			$wanif = "openvpn";
6060
			break;
6061
		case "IPsec":
6062
		case "ipsec":
6063
		case "enc0":
6064
			$wanif = "enc0";
6065
			break;
6066
		case "ppp":
6067
			$wanif = "ppp";
6068
			break;
6069
		default:
6070
			if (substr($interface, 0, 4) == '_vip') {
6071
				$wanif = get_configured_vip_interface($interface);
6072
				if (!empty($wanif)) {
6073
					$wanif = get_real_interface($wanif);
6074
				}
6075
				break;
6076
			} elseif (substr($interface, 0, 5) == '_lloc') {
6077
				$interface = substr($interface, 5);
6078
			} elseif (interface_is_vlan($interface) != NULL ||
6079
			    does_interface_exist($interface, $flush)) {
6080
				/*
6081
				 * If a real interface was already passed simply
6082
				 * pass the real interface back.  This encourages
6083
				 * the usage of this function in more cases so that
6084
				 * we can combine logic for more flexibility.
6085
				 */
6086
				$wanif = $interface;
6087
				break;
6088
			}
6089

    
6090
			if (empty($config['interfaces'][$interface])) {
6091
				break;
6092
			}
6093

    
6094
			$cfg = &$config['interfaces'][$interface];
6095

    
6096
			if ($family == "inet6") {
6097
				switch ($cfg['ipaddrv6']) {
6098
					case "6rd":
6099
					case "6to4":
6100
						$wanif = "{$interface}_stf";
6101
						break;
6102
					case 'pppoe':
6103
					case 'ppp':
6104
					case 'l2tp':
6105
					case 'pptp':
6106
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6107
							$wanif = interface_get_wireless_clone($cfg['if']);
6108
						} else {
6109
							$wanif = $cfg['if'];
6110
						}
6111
						break;
6112
					default:
6113
						switch ($cfg['ipaddr']) {
6114
							case 'pppoe':
6115
							case 'ppp':
6116
							case 'l2tp':
6117
							case 'pptp':
6118
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
6119
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) ||
6120
								    isset($cfg['ipv6usev4iface']) || isset($cfg['slaacusev4iface'])) {
6121
									$wanif = $cfg['if'];
6122
								} else {
6123
									$parents = get_parent_interface($interface);
6124
									if (!empty($parents[0])) {
6125
										$wanif = $parents[0];
6126
									} else {
6127
										$wanif = $cfg['if'];
6128
									}
6129
								}
6130
								break;
6131
							default:
6132
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6133
									$wanif = interface_get_wireless_clone($cfg['if']);
6134
								} else {
6135
									$wanif = $cfg['if'];
6136
								}
6137
								break;
6138
						}
6139
						break;
6140
				}
6141
			} else {
6142
				// Wireless cloned NIC support (FreeBSD 8+)
6143
				// interface name format: $parentnic_wlanparentnic#
6144
				// example: ath0_wlan0
6145
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6146
					$wanif = interface_get_wireless_clone($cfg['if']);
6147
				} else {
6148
					$wanif = $cfg['if'];
6149
				}
6150
			}
6151
			break;
6152
	}
6153

    
6154
	return $wanif;
6155
}
6156

    
6157
/* Guess the physical interface by providing a IP address */
6158
function guess_interface_from_ip($ipaddress) {
6159

    
6160
	if (!is_ipaddr($ipaddress)) {
6161
		return false;
6162
	}
6163

    
6164
	$route = route_get($ipaddress, '', true);
6165
	if (empty($route)) {
6166
		return false;
6167
	}
6168

    
6169
	if (!empty($route[0]['interface-name'])) {
6170
		return $route[0]['interface-name'];
6171
	}
6172

    
6173
	return false;
6174
}
6175

    
6176
/*
6177
 * find_ip_interface($ip): return the interface where an ip is defined
6178
 *   (or if $bits is specified, where an IP within the subnet is defined)
6179
 */
6180
function find_ip_interface($ip, $bits = null) {
6181
	if (!is_ipaddr($ip)) {
6182
		return false;
6183
	}
6184

    
6185
	$isv6ip = is_ipaddrv6($ip);
6186

    
6187
	/* if list */
6188
	$ifdescrs = get_configured_interface_list();
6189

    
6190
	foreach ($ifdescrs as $ifdescr => $ifname) {
6191
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
6192
		if (is_null($ifip)) {
6193
			continue;
6194
		}
6195
		if (is_null($bits)) {
6196
			if ($ip == $ifip) {
6197
				$int = get_real_interface($ifname);
6198
				return $int;
6199
			}
6200
		} else {
6201
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
6202
				$int = get_real_interface($ifname);
6203
				return $int;
6204
			}
6205
		}
6206
	}
6207

    
6208
	return false;
6209
}
6210

    
6211
/*
6212
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
6213
 *   (or if $bits is specified, where an IP within the subnet is found)
6214
 */
6215
function find_virtual_ip_alias($ip, $bits = null) {
6216
	global $config;
6217

    
6218
	if (!is_array($config['virtualip']['vip'])) {
6219
		return false;
6220
	}
6221
	if (!is_ipaddr($ip)) {
6222
		return false;
6223
	}
6224

    
6225
	$isv6ip = is_ipaddrv6($ip);
6226

    
6227
	foreach ($config['virtualip']['vip'] as $vip) {
6228
		if ($vip['mode'] === "ipalias") {
6229
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
6230
				continue;
6231
			}
6232
			if (is_null($bits)) {
6233
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
6234
					return $vip;
6235
				}
6236
			} else {
6237
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
6238
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
6239
					return $vip;
6240
				}
6241
			}
6242
		}
6243
	}
6244
	return false;
6245
}
6246

    
6247
function link_interface_to_track6($int, $action = "") {
6248
	global $config;
6249

    
6250
	if (empty($int)) {
6251
		return;
6252
	}
6253

    
6254
	if (is_array($config['interfaces'])) {
6255
		$list = array();
6256
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
6257
			if (!isset($ifcfg['enable'])) {
6258
				continue;
6259
			}
6260
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
6261
				if ($action == "update") {
6262
					interface_track6_configure($ifname, $ifcfg);
6263
				} elseif ($action == "") {
6264
					$list[$ifname] = $ifcfg;
6265
				}
6266
			}
6267
		}
6268
		return $list;
6269
	}
6270
}
6271

    
6272
function interface_find_child_cfgmtu($realiface) {
6273
	global $config;
6274

    
6275
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
6276
	$vlans = link_interface_to_vlans($realiface);
6277
	$qinqs = link_interface_to_qinqs($realiface);
6278
	$bridge = link_interface_to_bridge($realiface);
6279
	if (!empty($interface)) {
6280
		$gifs = link_interface_to_tunnelif($interface, 'gif');
6281
		$gres = link_interface_to_tunnelif($interface, 'gre');
6282
	} else {
6283
		$gifs = array();
6284
		$gres = array();
6285
	}
6286

    
6287
	$mtu = 0;
6288
	if (is_array($vlans)) {
6289
		foreach ($vlans as $vlan) {
6290
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
6291
			if (empty($ifass)) {
6292
				continue;
6293
			}
6294
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6295
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6296
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6297
				}
6298
			}
6299
		}
6300
	}
6301
	if (is_array($qinqs)) {
6302
		foreach ($qinqs as $qinq) {
6303
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
6304
			if (empty($ifass)) {
6305
				continue;
6306
			}
6307
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6308
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6309
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6310
				}
6311
			}
6312
		}
6313
	}
6314
	if (is_array($gifs)) {
6315
		foreach ($gifs as $gif) {
6316
			$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
6317
			if (empty($ifass)) {
6318
				continue;
6319
			}
6320
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6321
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6322
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6323
				}
6324
			}
6325
		}
6326
	}
6327
	if (is_array($gres)) {
6328
		foreach ($gres as $gre) {
6329
			$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
6330
			if (empty($ifass)) {
6331
				continue;
6332
			}
6333
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6334
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6335
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6336
				}
6337
			}
6338
		}
6339
	}
6340
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
6341
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
6342
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6343
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
6344
		}
6345
	}
6346
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
6347

    
6348
	return $mtu;
6349
}
6350

    
6351
function link_interface_to_vlans($int, $action = "") {
6352
	global $config;
6353

    
6354
	if (empty($int)) {
6355
		return;
6356
	}
6357

    
6358
	if (is_array($config['vlans']['vlan'])) {
6359
		$ifaces = array();
6360
		foreach ($config['vlans']['vlan'] as $vlan) {
6361
			if ($int == $vlan['if']) {
6362
				if ($action == "update") {
6363
					interfaces_bring_up($int);
6364
				} else {
6365
					$ifaces[$vlan['tag']] = $vlan;
6366
				}
6367
			}
6368
		}
6369
		if (!empty($ifaces)) {
6370
			return $ifaces;
6371
		}
6372
	}
6373
}
6374

    
6375
function link_interface_to_qinqs($int, $action = "") {
6376
	global $config;
6377

    
6378
	if (empty($int)) {
6379
		return;
6380
	}
6381

    
6382
	if (is_array($config['qinqs']['qinqentry'])) {
6383
		$ifaces = array();
6384
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
6385
			if ($int == $qinq['if']) {
6386
				if ($action == "update") {
6387
					interfaces_bring_up($int);
6388
				} else {
6389
					$ifaces[$qinq['tag']] = $qinq;
6390
				}
6391
			}
6392
		}
6393
		if (!empty($ifaces)) {
6394
			return $ifaces;
6395
		}
6396
	}
6397
}
6398

    
6399
function link_interface_to_vips($int, $action = "", $vhid = '') {
6400
	global $config;
6401

    
6402
	$updatevips = false;
6403
	if (is_array($config['virtualip']['vip'])) {
6404
		$result = array();
6405
		foreach ($config['virtualip']['vip'] as $vip) {
6406
			if (substr($vip['interface'], 0, 4) == "_vip") {
6407
				$iface = get_configured_vip_interface($vip['interface']);
6408
			} else {
6409
				$iface = $vip['interface'];
6410
			}
6411
			if ($int != $iface) {
6412
				continue;
6413
			}
6414
			if ($action == "update") {
6415
				$updatevips = true;
6416
			} else {
6417
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
6418
				    substr($vip['interface'], 0, 4) == "_vip") {
6419
					$result[] = $vip;
6420
				}
6421
			}
6422
		}
6423
		if ($updatevips === true) {
6424
			interfaces_vips_configure($int);
6425
		}
6426
		return $result;
6427
	}
6428

    
6429
	return NULL;
6430
}
6431

    
6432
/****f* interfaces/link_interface_to_bridge
6433
 * NAME
6434
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6435
 * INPUTS
6436
 *   $ip
6437
 * RESULT
6438
 *   bridge[0-99]
6439
 ******/
6440
function link_interface_to_bridge($int) {
6441
	global $config;
6442

    
6443
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged'])) {
6444
		foreach ($config['bridges']['bridged'] as $bridge) {
6445
			if (in_array($int, explode(',', $bridge['members']))) {
6446
				return "{$bridge['bridgeif']}";
6447
			}
6448
		}
6449
	}
6450
}
6451

    
6452
function link_interface_to_lagg($int) {
6453
	global $config;
6454

    
6455
	if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
6456
		foreach ($config['laggs']['lagg'] as $lagg) {
6457
			if (in_array($int, explode(',', $lagg['members']))) {
6458
				return "{$lagg['laggif']}";
6459
			}
6460
		}
6461
	}
6462
}
6463

    
6464
function link_interface_to_group($int) {
6465
	global $config;
6466

    
6467
	$result = array();
6468

    
6469
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
6470
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
6471
			if (in_array($int, explode(" ", $group['members']))) {
6472
				$result[$group['ifname']] = $int;
6473
			}
6474
		}
6475
	}
6476

    
6477
	return $result;
6478
}
6479

    
6480
function link_interface_to_tunnelif($interface, $type) {
6481
	global $config;
6482

    
6483
	if (!in_array($type, array('gre', 'gif'))) {
6484
		return;
6485
	}
6486

    
6487
	$result = array();
6488

    
6489
	if (is_array($config["{$type}s"][$type])) {
6490
		foreach ($config["{$type}s"][$type] as $tunnel) {
6491
			if ($tunnel['if'] == $interface) {
6492
				$result[] = $tunnel;
6493
			}
6494
		}
6495
	}
6496

    
6497
	return $result;
6498
}
6499

    
6500
/*
6501
 * find_interface_ip($interface): return the interface ip (first found)
6502
 */
6503
function find_interface_ip($interface, $flush = false) {
6504
	global $interface_ip_arr_cache;
6505
	global $interface_sn_arr_cache;
6506

    
6507
	$interface = str_replace("\n", "", $interface);
6508

    
6509
	if (!does_interface_exist($interface)) {
6510
		return;
6511
	}
6512

    
6513
	/* Setup IP cache */
6514
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6515
		if (file_exists("/var/db/${interface}_ip")) {
6516
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6517
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6518
			foreach ($ifaddrs as $ifaddr) {
6519
				list($ip, $mask) = explode("/", $ifaddr);
6520
				if ($ip == $ifip) {
6521
					$interface_ip_arr_cache[$interface] = $ip;
6522
					$interface_sn_arr_cache[$interface] = $mask;
6523
					break;
6524
				}
6525
			}
6526
		}
6527
		if (!isset($interface_ip_arr_cache[$interface])) {
6528
			$ifinfo = pfSense_get_interface_addresses($interface);
6529
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6530
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6531
		}
6532
	}
6533

    
6534
	return $interface_ip_arr_cache[$interface];
6535
}
6536

    
6537
/*
6538
 * find_interface_ipv6($interface): return the interface ip (first found)
6539
 */
6540
function find_interface_ipv6($interface, $flush = false) {
6541
	global $interface_ipv6_arr_cache;
6542
	global $interface_snv6_arr_cache;
6543
	global $config;
6544

    
6545
	$interface = trim($interface);
6546
	$interface = get_real_interface($interface);
6547

    
6548
	if (!does_interface_exist($interface)) {
6549
		return;
6550
	}
6551

    
6552
	/* Setup IP cache */
6553
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6554
		$ifinfo = pfSense_get_interface_addresses($interface);
6555
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6556
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6557
	}
6558

    
6559
	return $interface_ipv6_arr_cache[$interface];
6560
}
6561

    
6562
/*
6563
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6564
 */
6565
function find_interface_ipv6_ll($interface, $flush = false) {
6566
	global $interface_llv6_arr_cache;
6567
	global $config;
6568

    
6569
	$interface = str_replace("\n", "", $interface);
6570

    
6571
	if (!does_interface_exist($interface)) {
6572
		return;
6573
	}
6574

    
6575
	/* Setup IP cache */
6576
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6577
		$ifinfo = pfSense_getall_interface_addresses($interface);
6578
		foreach ($ifinfo as $line) {
6579
			if (strstr($line, ":")) {
6580
				$parts = explode("/", $line);
6581
				if (is_linklocal($parts[0])) {
6582
					$ifinfo['linklocal'] = $parts[0];
6583
				}
6584
			}
6585
		}
6586
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6587
	}
6588
	return $interface_llv6_arr_cache[$interface];
6589
}
6590

    
6591
function find_interface_subnet($interface, $flush = false) {
6592
	global $interface_sn_arr_cache;
6593
	global $interface_ip_arr_cache;
6594

    
6595
	$interface = str_replace("\n", "", $interface);
6596
	if (does_interface_exist($interface) == false) {
6597
		return;
6598
	}
6599

    
6600
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6601
		$ifinfo = pfSense_get_interface_addresses($interface);
6602
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6603
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6604
	}
6605

    
6606
	return $interface_sn_arr_cache[$interface];
6607
}
6608

    
6609
function find_interface_subnetv6($interface, $flush = false) {
6610
	global $interface_snv6_arr_cache;
6611
	global $interface_ipv6_arr_cache;
6612

    
6613
	$interface = str_replace("\n", "", $interface);
6614
	if (does_interface_exist($interface) == false) {
6615
		return;
6616
	}
6617

    
6618
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6619
		$ifinfo = pfSense_get_interface_addresses($interface);
6620
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6621
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6622
	}
6623

    
6624
	return $interface_snv6_arr_cache[$interface];
6625
}
6626

    
6627
function ip_in_interface_alias_subnet($interface, $ipalias) {
6628
	global $config;
6629

    
6630
	if (empty($interface) || !is_ipaddr($ipalias)) {
6631
		return false;
6632
	}
6633
	if (is_array($config['virtualip']['vip'])) {
6634
		foreach ($config['virtualip']['vip'] as $vip) {
6635
			switch ($vip['mode']) {
6636
				case "ipalias":
6637
					if ($vip['interface'] <> $interface) {
6638
						break;
6639
					}
6640
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6641
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6642
						return true;
6643
					}
6644
					break;
6645
			}
6646
		}
6647
	}
6648

    
6649
	return false;
6650
}
6651

    
6652
function get_possible_listen_ips($include_ipv6_link_local=false) {
6653

    
6654
	$interfaces = get_configured_interface_with_descr();
6655
	foreach ($interfaces as $iface => $ifacename) {
6656
		if ($include_ipv6_link_local) {
6657
			/* This is to avoid going though added ll below */
6658
			if (substr($iface, 0, 5) == '_lloc') {
6659
				continue;
6660
			}
6661
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6662
			if (!empty($llip)) {
6663
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6664
			}
6665
		}
6666
	}
6667
	$viplist = get_configured_vip_list();
6668
	foreach ($viplist as $vip => $address) {
6669
		$interfaces[$vip] = $address;
6670
		if (get_vip_descr($address)) {
6671
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6672
		}
6673
	}
6674

    
6675
	$interfaces['lo0'] = 'Localhost';
6676

    
6677
	return $interfaces;
6678
}
6679

    
6680
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6681
	global $config;
6682

    
6683
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6684
	foreach (array('server', 'client') as $mode) {
6685
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
6686
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
6687
				if (!isset($setting['disable'])) {
6688
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6689
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6690
				}
6691
			}
6692
		}
6693
	}
6694
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
6695
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
6696
			if ($ph1ent['disabled']) {
6697
				continue;
6698
			}
6699
			if (ipsec_vti($ph1ent)) {
6700
				$sourceips_key = "ipsec{$ph1ent['ikeid']}";
6701
				$sourceips[$sourceips_key] = gettext("IPsec VTI") . ": " . htmlspecialchars($ph1ent['descr']);
6702
			}
6703
		}
6704
	}
6705
	return $sourceips;
6706
}
6707

    
6708
function get_interface_ip($interface = "wan") {
6709
	global $config;
6710

    
6711
	if (substr($interface, 0, 4) == '_vip') {
6712
		return get_configured_vip_ipv4($interface);
6713
	} elseif (substr($interface, 0, 5) == '_lloc') {
6714
		/* No link-local address for v4. */
6715
		return null;
6716
	}
6717

    
6718
	$realif = get_failover_interface($interface, 'inet');
6719
	if (!$realif) {
6720
		return null;
6721
	}
6722

    
6723
	if (substr($realif, 0, 4) == '_vip') {
6724
		return get_configured_vip_ipv4($realif);
6725
	} elseif (substr($realif, 0, 5) == '_lloc') {
6726
		/* No link-local address for v4. */
6727
		return null;
6728
	}
6729

    
6730
	if (is_array($config['interfaces'][$interface]) &&
6731
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6732
		return ($config['interfaces'][$interface]['ipaddr']);
6733
	}
6734

    
6735
	/*
6736
	 * Beaware that find_interface_ip() is our last option, it will
6737
	 * return the first IP it find on interface, not necessarily the
6738
	 * main IP address.
6739
	 */
6740
	$curip = find_interface_ip($realif);
6741
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6742
		return $curip;
6743
	} else {
6744
		return null;
6745
	}
6746
}
6747

    
6748
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6749
	global $config;
6750

    
6751
	if (substr($interface, 0, 4) == '_vip') {
6752
		return get_configured_vip_ipv6($interface);
6753
	} elseif (substr($interface, 0, 5) == '_lloc') {
6754
		return get_interface_linklocal($interface);
6755
	}
6756

    
6757
	$realif = get_failover_interface($interface, 'inet6');
6758
	if (!$realif) {
6759
		return null;
6760
	}
6761

    
6762
	if (substr($realif, 0, 4) == '_vip') {
6763
		return get_configured_vip_ipv6($realif);
6764
	} elseif (substr($realif, 0, 5) == '_lloc') {
6765
		return get_interface_linklocal($realif);
6766
	}
6767

    
6768
	if (is_array($config['interfaces'][$interface])) {
6769
		switch ($config['interfaces'][$interface]['ipaddr']) {
6770
			case 'pppoe':
6771
			case 'l2tp':
6772
			case 'pptp':
6773
			case 'ppp':
6774
				if (($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') ||
6775
				    ($config['interfaces'][$interface]['ipaddrv6'] == 'slaac')) {
6776
					$realif = get_real_interface($interface, 'inet6', false);
6777
				}
6778
				break;
6779
		}
6780
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6781
			return ($config['interfaces'][$interface]['ipaddrv6']);
6782
		}
6783
	}
6784

    
6785
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6786
	if ($config['interfaces'][$interface]['ipaddrv6'] == 'track6') {
6787
		$curip = get_interface_track6ip($interface);
6788
		if ($curip) {
6789
			return $curip[0];
6790
		}
6791
	}
6792

    
6793
	/*
6794
	 * Beaware that find_interface_ip() is our last option, it will
6795
	 * return the first IP it find on interface, not necessarily the
6796
	 * main IP address.
6797
	 */
6798
	$curip = find_interface_ipv6($realif, $flush);
6799
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6800
		return $curip;
6801
	} else {
6802
		/*
6803
		 * NOTE: On the case when only the prefix is requested,
6804
		 * the communication on WAN will be done over link-local.
6805
		 */
6806
		if ($linklocal_fallback || (is_array($config['interfaces'][$interface]) && isset($config['interfaces'][$interface]['dhcp6prefixonly']))) {
6807
			$curip = find_interface_ipv6_ll($realif, $flush);
6808
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6809
				return $curip;
6810
			}
6811
		}
6812
	}
6813
	return null;
6814
}
6815

    
6816
function get_interface_linklocal($interface = "wan") {
6817

    
6818
	$realif = get_failover_interface($interface, 'inet6');
6819
	if (!$realif) {
6820
		return null;
6821
	}
6822

    
6823
	if (substr($interface, 0, 4) == '_vip') {
6824
		$realif = get_real_interface($interface);
6825
	} elseif (substr($interface, 0, 5) == '_lloc') {
6826
		$realif = get_real_interface(substr($interface, 5));
6827
	}
6828

    
6829
	$curip = find_interface_ipv6_ll($realif);
6830
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6831
		return $curip;
6832
	} else {
6833
		return null;
6834
	}
6835
}
6836

    
6837
function get_interface_track6ip($interface = "wan") {
6838
	$realif = get_real_interface($interface);
6839
	$vips = get_configured_vip_list('inet6');
6840

    
6841
	foreach (pfSense_getall_interface_addresses($realif) as $ifaddr) {
6842
		list($ip, $bits) = explode("/", $ifaddr);
6843
		$ip = text_to_compressed_ip6($ip);
6844
		if (is_ipaddrv6($ip) && !is_linklocal($ip)) {
6845
			if (is_array($vips) && !empty($vips)) {
6846
				foreach ($vips as $vip) {
6847
					if ($ip == text_to_compressed_ip6($vip)) {
6848
						continue 2;
6849
					}
6850
				}
6851
			}
6852
			return array($ip, $bits);
6853
		}
6854
	}
6855
	return false;
6856
}
6857

    
6858
function get_interface_subnet($interface = "wan") {
6859
	global $config;
6860

    
6861
	if (substr($interface, 0, 4) == '_vip') {
6862
		return (get_configured_vip_subnetv4($interface));
6863
	}
6864

    
6865
	if (is_array($config['interfaces'][$interface]) &&
6866
	    !empty($config['interfaces'][$interface]['subnet']) &&
6867
	    is_ipaddrv4($config['interfaces'][$interface]['ipaddr'])) {
6868
		return ($config['interfaces'][$interface]['subnet']);
6869
	}
6870

    
6871
	$realif = get_real_interface($interface);
6872
	if (!$realif) {
6873
		return (NULL);
6874
	}
6875

    
6876
	$cursn = find_interface_subnet($realif);
6877
	if (!empty($cursn)) {
6878
		return ($cursn);
6879
	}
6880

    
6881
	return (NULL);
6882
}
6883

    
6884
function get_interface_subnetv6($interface = "wan") {
6885
	global $config;
6886

    
6887
	if (substr($interface, 0, 4) == '_vip') {
6888
		return (get_configured_vip_subnetv6($interface));
6889
	} elseif (substr($interface, 0, 5) == '_lloc') {
6890
		$interface = substr($interface, 5);
6891
	}
6892

    
6893
	if (is_array($config['interfaces'][$interface]) &&
6894
	    !empty($config['interfaces'][$interface]['subnetv6']) &&
6895
	    is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6896
		return ($config['interfaces'][$interface]['subnetv6']);
6897
	}
6898

    
6899
	$realif = get_real_interface($interface, 'inet6');
6900
	if (!$realif) {
6901
		return (NULL);
6902
	}
6903

    
6904
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6905
	if ($config['interfaces'][$interface]['ipaddrv6'] == 'track6') {
6906
		$curip = get_interface_track6ip($interface);
6907
		if ($curip) {
6908
			return $curip[1];
6909
		}
6910
	}
6911

    
6912
	$cursn = find_interface_subnetv6($realif);
6913
	if (!empty($cursn)) {
6914
		return ($cursn);
6915
	}
6916

    
6917
	return (NULL);
6918
}
6919

    
6920
/* return outside interfaces with a gateway */
6921
function get_interfaces_with_gateway() {
6922
	global $config;
6923

    
6924
	$ints = array();
6925

    
6926
	/* loop interfaces, check config for outbound */
6927
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6928
		switch ($ifname['ipaddr']) {
6929
			case "dhcp":
6930
			case "pppoe":
6931
			case "pptp":
6932
			case "l2tp":
6933
			case "ppp":
6934
				$ints[$ifdescr] = $ifdescr;
6935
				break;
6936
			default:
6937
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6938
				    !empty($ifname['gateway'])) {
6939
					$ints[$ifdescr] = $ifdescr;
6940
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6941
				    !empty($ifname['gateway'])) {
6942
					$ints[$ifdescr] = $ifdescr;
6943
				} elseif (substr($ifname['if'], 0, 2) == "wg" ||
6944
				    !empty($ifname['gateway'])) {
6945
					$ints[$ifdescr] = $ifdescr;
6946
				}
6947

    
6948
				break;
6949
		}
6950
	}
6951
	return $ints;
6952
}
6953

    
6954
/* return true if interface has a gateway */
6955
function interface_has_gateway($friendly) {
6956
	global $config;
6957

    
6958
	if (!empty($config['interfaces'][$friendly])) {
6959
		$ifname = &$config['interfaces'][$friendly];
6960
		switch ($ifname['ipaddr']) {
6961
			case "dhcp":
6962
				/* see https://redmine.pfsense.org/issues/5135 */
6963
				if (get_interface_gateway($friendly)) {
6964
					return true;
6965
				}
6966
				break;
6967
			case "pppoe":
6968
			case "pptp":
6969
			case "l2tp":
6970
			case "ppp":
6971
				return true;
6972
				break;
6973
			default:
6974
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6975
				    (substr($ifname['if'], 0, 5) == "ipsec") ||
6976
				    (substr($ifname['if'], 0, 2) == "wg")) {
6977
					return true;
6978
				}
6979
				$tunnelif = substr($ifname['if'], 0, 3);
6980
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6981
					if (find_interface_ip($ifname['if'])) {
6982
						return true;
6983
					}
6984
				}
6985
				if (!empty($ifname['gateway'])) {
6986
					return true;
6987
				}
6988
				break;
6989
		}
6990
	}
6991

    
6992
	return false;
6993
}
6994

    
6995
/* return true if interface has a gateway */
6996
function interface_has_gatewayv6($friendly) {
6997
	global $config;
6998

    
6999
	if (!empty($config['interfaces'][$friendly])) {
7000
		$ifname = &$config['interfaces'][$friendly];
7001
		switch ($ifname['ipaddrv6']) {
7002
			case "slaac":
7003
			case "dhcp6":
7004
			case "6to4":
7005
			case "6rd":
7006
				return true;
7007
				break;
7008
			default:
7009
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
7010
				    (substr($ifname['if'], 0, 5) == "ipsec") ||
7011
				    (substr($ifname['if'], 0, 2) == "wg")) {
7012
					return true;
7013
				}
7014
				$tunnelif = substr($ifname['if'], 0, 3);
7015
				if ($tunnelif == "gif" || $tunnelif == "gre") {
7016
					if (find_interface_ipv6($ifname['if'])) {
7017
						return true;
7018
					}
7019
				}
7020
				if (!empty($ifname['gatewayv6'])) {
7021
					return true;
7022
				}
7023
				break;
7024
		}
7025
	}
7026

    
7027
	return false;
7028
}
7029

    
7030
/****f* interfaces/is_altq_capable
7031
 * NAME
7032
 *   is_altq_capable - Test if interface is capable of using ALTQ
7033
 * INPUTS
7034
 *   $int            - string containing interface name
7035
 * RESULT
7036
 *   boolean         - true or false
7037
 ******/
7038

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

    
7054
	$int_family = remove_ifindex($int);
7055

    
7056
	if (in_array($int_family, $capable)) {
7057
		return true;
7058
	} elseif (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
7059
		return true;
7060
	} elseif (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
7061
		return true;
7062
	} elseif (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
7063
		return true;
7064
	} else {
7065
		return false;
7066
	}
7067
}
7068

    
7069
/****f* interfaces/is_interface_wireless
7070
 * NAME
7071
 *   is_interface_wireless - Returns if an interface is wireless
7072
 * RESULT
7073
 *   $tmp       - Returns if an interface is wireless
7074
 ******/
7075
function is_interface_wireless($interface) {
7076
	global $config, $g;
7077

    
7078
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
7079
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
7080
		if (preg_match($g['wireless_regex'], $interface)) {
7081
			if (isset($config['interfaces'][$friendly])) {
7082
				$config['interfaces'][$friendly]['wireless'] = array();
7083
			}
7084
			return true;
7085
		}
7086
		return false;
7087
	} else {
7088
		return true;
7089
	}
7090
}
7091

    
7092
function get_wireless_modes($interface) {
7093
	/* return wireless modes and channels */
7094
	$wireless_modes = array();
7095

    
7096
	$cloned_interface = get_real_interface($interface);
7097

    
7098
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7099
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
7100
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
7101
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
7102

    
7103
		$interface_channels = "";
7104
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
7105
		$interface_channel_count = count($interface_channels);
7106

    
7107
		$c = 0;
7108
		while ($c < $interface_channel_count) {
7109
			$channel_line = explode(",", $interface_channels["$c"]);
7110
			$wireless_mode = trim($channel_line[0]);
7111
			$wireless_channel = trim($channel_line[1]);
7112
			if (trim($wireless_mode) != "") {
7113
				/* if we only have 11g also set 11b channels */
7114
				if ($wireless_mode == "11g") {
7115
					if (!isset($wireless_modes["11b"])) {
7116
						$wireless_modes["11b"] = array();
7117
					}
7118
				} elseif ($wireless_mode == "11g ht") {
7119
					if (!isset($wireless_modes["11b"])) {
7120
						$wireless_modes["11b"] = array();
7121
					}
7122
					if (!isset($wireless_modes["11g"])) {
7123
						$wireless_modes["11g"] = array();
7124
					}
7125
					$wireless_mode = "11ng";
7126
				} elseif ($wireless_mode == "11a ht") {
7127
					if (!isset($wireless_modes["11a"])) {
7128
						$wireless_modes["11a"] = array();
7129
					}
7130
					$wireless_mode = "11na";
7131
				}
7132
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
7133
			}
7134
			$c++;
7135
		}
7136
	}
7137
	return($wireless_modes);
7138
}
7139

    
7140
function get_wireless_channels($interface) {
7141
		$chan_list = "/sbin/ifconfig -v " . escapeshellarg($interface) . " list chan";
7142
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
7143
		$format_list = "/usr/bin/awk '{print \$5 \",\" \$6 \",\" \$1}'";
7144

    
7145
		$interface_channels = "";
7146
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7147
		return $interface_channels;
7148
}
7149

    
7150
/* return wireless HT modes */
7151
function get_wireless_ht_modes($interface) {
7152
	$wireless_hts_supported = array(0 => gettext('Auto'));
7153

    
7154
	$cloned_interface = get_real_interface($interface);
7155

    
7156
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7157
		$interface_channels = get_wireless_channels($cloned_interface);
7158

    
7159
		foreach ($interface_channels as $channel) {
7160
			$channel_line = explode(",", $channel);
7161
			$wireless_ht = trim($channel_line[1]);
7162
			if (!empty($wireless_ht)) {
7163
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
7164
			}
7165
		}
7166
	}
7167
	return($wireless_hts_supported);
7168
}
7169

    
7170
/* return wireless HT by channel/standard */
7171
function get_wireless_ht_list($interface) {
7172
	$wireless_hts = array();
7173

    
7174
	$cloned_interface = get_real_interface($interface);
7175

    
7176
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7177
		$interface_channels = get_wireless_channels($cloned_interface);
7178
		$interface_channel_count = count($interface_channels);
7179

    
7180
		$c = 0;
7181
		while ($c < $interface_channel_count) {
7182
			$channel_line = explode(",", $interface_channels["$c"]);
7183
			$wireless_mode = trim($channel_line[0]);
7184
			$wireless_ht = trim($channel_line[1]);
7185
			$wireless_channel = trim($channel_line[2]);
7186
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
7187
				if ($wireless_mode == "11g") {
7188
					if (!isset($wireless_modes["11g"])) {
7189
						$wireless_hts["11g"] = array();
7190
					}
7191
					$wireless_mode = "11ng";
7192
				} elseif ($wireless_mode == "11a") {
7193
					if (!isset($wireless_modes["11a"])) {
7194
						$wireless_hts["11a"] = array();
7195
					}
7196
					$wireless_mode = "11na";
7197
				}
7198
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
7199
			}
7200
			$c++;
7201
		}
7202
	}
7203
	return($wireless_hts);
7204
}
7205

    
7206
/* return channel numbers, frequency, max txpower, and max regulation txpower */
7207
function get_wireless_channel_info($interface) {
7208
	$wireless_channels = array();
7209

    
7210
	$cloned_interface = get_real_interface($interface);
7211

    
7212
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7213
		$chan_list = "/sbin/ifconfig " . escapeshellarg($cloned_interface) . " list txpower";
7214
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
7215
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
7216

    
7217
		$interface_channels = "";
7218
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7219

    
7220
		foreach ($interface_channels as $channel_line) {
7221
			$channel_line = explode(",", $channel_line);
7222
			if (!isset($wireless_channels[$channel_line[0]])) {
7223
				$wireless_channels[$channel_line[0]] = $channel_line;
7224
			}
7225
		}
7226
	}
7227
	return($wireless_channels);
7228
}
7229

    
7230
function set_interface_mtu($interface, $mtu) {
7231

    
7232
	/* LAGG interface must be destroyed and re-created to change MTU */
7233
	if ((substr($interface, 0, 4) == 'lagg') &&
7234
	    (!strstr($interface, "."))) {
7235
		if (isset($config['laggs']['lagg']) &&
7236
		    is_array($config['laggs']['lagg'])) {
7237
			foreach ($config['laggs']['lagg'] as $lagg) {
7238
				if ($lagg['laggif'] == $interface) {
7239
					interface_lagg_configure($lagg);
7240
					break;
7241
				}
7242
			}
7243
		}
7244
	} else {
7245
		pfSense_interface_mtu($interface, $mtu);
7246
		set_ipv6routes_mtu($interface, $mtu);
7247
	}
7248
}
7249

    
7250
/****f* interfaces/get_interface_mtu
7251
 * NAME
7252
 *   get_interface_mtu - Return the mtu of an interface
7253
 * RESULT
7254
 *   $tmp       - Returns the mtu of an interface
7255
 ******/
7256
function get_interface_mtu($interface) {
7257
	$mtu = pfSense_interface_getmtu($interface);
7258
	return $mtu['mtu'];
7259
}
7260

    
7261
function get_interface_mac($interface) {
7262
	$macinfo = pfSense_get_interface_addresses($interface);
7263
	return $macinfo["macaddr"];
7264
}
7265

    
7266
function get_interface_vendor_mac($interface) {
7267
	global $config, $g;
7268

    
7269
	$macinfo = pfSense_get_interface_addresses($interface);
7270
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7271
	    "00:00:00:00:00:00") {
7272
		return ($macinfo["hwaddr"]);
7273
	}
7274

    
7275
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7276
	if (file_exists($hwaddr_file)) {
7277
		$macaddr = trim(file_get_contents($hwaddr_file));
7278
		if (is_macaddr($macaddr)) {
7279
			return ($macaddr);
7280
		}
7281
	} elseif (is_macaddr($macinfo['macaddr'])) {
7282
		/* Save original macaddress to be restored when necessary */
7283
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7284
	}
7285

    
7286
	return (NULL);
7287
}
7288

    
7289
/****f* pfsense-utils/generate_random_mac_address
7290
 * NAME
7291
 *   generate_random_mac - generates a random mac address
7292
 * INPUTS
7293
 *   none
7294
 * RESULT
7295
 *   $mac - a random mac address
7296
 ******/
7297
function generate_random_mac_address() {
7298
	$mac = "02";
7299
	for ($x = 0; $x < 5; $x++) {
7300
		$mac .= ":" . dechex(rand(16, 255));
7301
	}
7302
	return $mac;
7303
}
7304

    
7305
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7306
	global $g;
7307

    
7308
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7309

    
7310
	if (!empty($iface) && !empty($pppif)) {
7311
		$cron_cmd = <<<EOD
7312
#!/bin/sh
7313
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7314
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7315

    
7316
EOD;
7317

    
7318
		@file_put_contents($cron_file, $cron_cmd);
7319
		chmod($cron_file, 0755);
7320
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7321
	} else {
7322
		unlink_if_exists($cron_file);
7323
	}
7324
}
7325

    
7326
function get_interface_default_mtu($type = "ethernet") {
7327
	switch ($type) {
7328
		case "gre":
7329
			return 1476;
7330
			break;
7331
		case "gif":
7332
			return 1280;
7333
			break;
7334
		case "wg":
7335
			return 1420;
7336
			break;
7337
		case "tun":
7338
		case "vlan":
7339
		case "tap":
7340
		case "ethernet":
7341
		default:
7342
			return 1500;
7343
			break;
7344
	}
7345

    
7346
	/* Never reached */
7347
	return 1500;
7348
}
7349

    
7350
function get_vip_descr($ipaddress) {
7351
	global $config;
7352

    
7353
	foreach ($config['virtualip']['vip'] as $vip) {
7354
		if ($vip['subnet'] == $ipaddress) {
7355
			return ($vip['descr']);
7356
		}
7357
	}
7358
	return "";
7359
}
7360

    
7361
function interfaces_staticarp_configure($if) {
7362
	global $config, $g;
7363
	if (isset($config['system']['developerspew'])) {
7364
		$mt = microtime();
7365
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7366
	}
7367

    
7368
	$ifcfg = $config['interfaces'][$if];
7369

    
7370
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
7371
		return 0;
7372
	}
7373

    
7374
	/* Enable staticarp, if enabled */
7375
	if (isset($config['dhcpd'][$if]['staticarp'])) {
7376
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7377
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7378
	} else {
7379
		/*
7380
		 * Interfaces do not have staticarp enabled by default
7381
		 * Let's not disable staticarp on freshly created interfaces
7382
		 */
7383
		if (!platform_booting()) {
7384
			mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7385
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7386
		}
7387
	}
7388

    
7389
	/* Enable static arp entries */
7390
	if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
7391
		foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
7392
			if (empty($arpent['ipaddr']) || empty($arpent['mac'])) {
7393
				continue;
7394
			}
7395
			if (isset($config['dhcpd'][$if]['staticarp']) || isset($arpent['arp_table_static_entry'])) {
7396
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7397
			}
7398
		}
7399
	}
7400

    
7401
	return 0;
7402
}
7403

    
7404
function get_failover_interface($interface, $family = "all") {
7405
	global $config;
7406

    
7407
	/* shortcut to get_real_interface if we find it in the config */
7408
	if (is_array($config['interfaces'][$interface])) {
7409
		return get_real_interface($interface, $family);
7410
	}
7411

    
7412
	/* compare against gateway groups */
7413
	$a_groups = return_gateway_groups_array(true);
7414
	if (is_array($a_groups[$interface])) {
7415
		/* we found a gateway group, fetch the interface or vip */
7416
		if (!empty($a_groups[$interface][0]['vip'])) {
7417
			return $a_groups[$interface][0]['vip'];
7418
		} else {
7419
			return $a_groups[$interface][0]['int'];
7420
		}
7421
	}
7422
	/* fall through to get_real_interface */
7423
	/* XXX: Really needed? */
7424
	return get_real_interface($interface, $family);
7425
}
7426

    
7427
/****f* interfaces/interface_has_dhcp
7428
 * NAME
7429
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7430
 * INPUTS
7431
 *   interface or gateway group name
7432
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7433
 * RESULT
7434
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7435
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7436
 ******/
7437
function interface_has_dhcp($interface, $family = 4) {
7438
	global $config;
7439

    
7440
	if ($config['interfaces'][$interface]) {
7441
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
7442
			return true;
7443
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
7444
			return true;
7445
		} else {
7446
			return false;
7447
		}
7448
	}
7449

    
7450
	if (!is_array($config['gateways']['gateway_group'])) {
7451
		return false;
7452
	}
7453

    
7454
	if ($family == 6) {
7455
		$dhcp_string = "_DHCP6";
7456
	} else {
7457
		$dhcp_string = "_DHCP";
7458
	}
7459

    
7460
	foreach ($config['gateways']['gateway_group'] as $group) {
7461
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7462
			continue;
7463
		}
7464
		foreach ($group['item'] as $item) {
7465
			$item_data = explode("|", $item);
7466
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7467
				return true;
7468
			}
7469
		}
7470
	}
7471

    
7472
	return false;
7473
}
7474

    
7475
function remove_ifindex($ifname) {
7476
	return preg_replace("/[0-9]+$/", "", $ifname);
7477
}
7478

    
7479
function get_configured_vip_list_with_descr($family = 'all', $type = VIP_ALL) {
7480
	$interfaces = array();	// In case there are no VIPs defined
7481

    
7482
	$viplist = get_configured_vip_list($family, $type);
7483
	foreach ($viplist as $vip => $address) {
7484
		$interfaces[$vip] = $address;
7485
		if ($type = VIP_CARP) {
7486
			$vip = get_configured_vip($vipid);
7487
			if (isset($vip) && is_array($vip) ) {
7488
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7489
			}
7490
		}
7491
		if (get_vip_descr($address)) {
7492
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
7493
		}
7494
	}
7495
	return $interfaces;
7496
}
7497

    
7498
function return_gateway_groups_array_with_descr() {
7499
	$interfaces = array();
7500
	$grouplist = return_gateway_groups_array();
7501
	foreach ($grouplist as $name => $group) {
7502
		if ($group[0]['vip'] != "") {
7503
			$vipif = $group[0]['vip'];
7504
		} else {
7505
			$vipif = $group[0]['int'];
7506
		}
7507

    
7508
		$interfaces[$name] = "GW Group {$name}";
7509
	}
7510
	return $interfaces;
7511
}
7512

    
7513
function get_serial_ports() {
7514
	$linklist = array();
7515
	if (!is_dir("/var/spool/lock")) {
7516
		mwexec("/bin/mkdir -p /var/spool/lock");
7517
	}
7518
	$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);
7519
	foreach ($serialports as $port) {
7520
		$linklist[$port] = trim($port);
7521
	}
7522
	return $linklist;
7523
}
7524

    
7525
function get_interface_ports() {
7526
	global $config;
7527
	$linklist = array();
7528
	$portlist = get_interface_list();
7529
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
7530
		foreach ($config['vlans']['vlan'] as $vlan) {
7531
			$portlist[$vlan['vlanif']] = $vlan;
7532
		}
7533
	}
7534

    
7535
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
7536
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
7537
			$members = explode(" ", $qinq['members']);
7538
			foreach ($members as $mem) {
7539
				$qentry = $qinq['vlanif'] . "." . $mem;
7540
				$portlist[$qentry] = $qentry;
7541
			}
7542
		}
7543
	}
7544

    
7545
	foreach ($portlist as $ifn => $ifinfo) {
7546
		$string = "";
7547
		if (is_array($ifinfo)) {
7548
			$string .= $ifn;
7549
			if ($ifinfo['mac']) {
7550
				$string .= " ({$ifinfo['mac']})";
7551
			}
7552
			if ($ifinfo['friendly']) {
7553
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7554
			} elseif ($ifinfo['descr']) {
7555
				$string .= " - {$ifinfo['descr']}";
7556
			}
7557
		} else {
7558
			$string .= $ifinfo;
7559
		}
7560

    
7561
		$linklist[$ifn] = $string;
7562
	}
7563
	return $linklist;
7564
}
7565

    
7566
function build_ppps_link_list() {
7567
	global $pconfig;
7568

    
7569
	$linklist = array('list' => array(), 'selected' => array());
7570

    
7571
	if ($pconfig['type'] == 'ppp') {
7572
		$linklist['list'] = get_serial_ports();
7573
	} else {
7574
		$iflist = get_interface_ports();
7575

    
7576
		$viplist = array();
7577
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7578
		foreach ($carplist as $vid => $vaddr) {
7579
			$vip = get_configured_vip($vid);
7580
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7581
		}
7582

    
7583
		$linklist['list'] = array_merge($iflist, $viplist);
7584

    
7585
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7586
		$lagglist = get_lagg_interface_list();
7587
		foreach ($lagglist as $laggif => $lagg) {
7588
			/* LAGG members cannot be assigned */
7589
			$laggmembers = explode(',', $lagg['members']);
7590
			foreach ($laggmembers as $lagm) {
7591
				if (isset($linklist['list'][$lagm])) {
7592
					unset($linklist['list'][$lagm]);
7593
				}
7594
			}
7595
		}
7596
	}
7597

    
7598
	$selected_ports = array();
7599
	if (is_array($pconfig['interfaces'])) {
7600
		$selected_ports = $pconfig['interfaces'];
7601
	} elseif (!empty($pconfig['interfaces'])) {
7602
		$selected_ports = explode(',', $pconfig['interfaces']);
7603
	}
7604
	foreach ($selected_ports as $port) {
7605
		if (isset($linklist['list'][$port])) {
7606
			array_push($linklist['selected'], $port);
7607
		}
7608
	}
7609
	return($linklist);
7610
}
7611

    
7612
function create_interface_list() {
7613
	global $config;
7614

    
7615
	$iflist = array();
7616

    
7617
	// add group interfaces
7618
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
7619
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
7620
			if (have_ruleint_access($ifgen['ifname'])) {
7621
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7622
			}
7623
		}
7624
	}
7625

    
7626
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7627
		if (have_ruleint_access($ifent)) {
7628
			$iflist[$ifent] = $ifdesc;
7629
		}
7630
	}
7631

    
7632
	if ($config['l2tp']['mode'] == "server" && have_ruleint_access("l2tp")) {
7633
		$iflist['l2tp'] = gettext('L2TP VPN');
7634
	}
7635

    
7636
	if (is_pppoe_server_enabled() && have_ruleint_access("pppoe")) {
7637
		$iflist['pppoe'] = gettext("PPPoE Server");
7638
	}
7639

    
7640
	// add ipsec interfaces
7641
	if (ipsec_enabled() && have_ruleint_access("enc0")) {
7642
		$iflist["enc0"] = gettext("IPsec");
7643
	}
7644

    
7645
	// add openvpn/tun interfaces
7646
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7647
		$iflist["openvpn"] = gettext("OpenVPN");
7648
	}
7649

    
7650
	if (is_wg_enabled() && have_ruleint_access("wireguard")) {
7651
		$iflist['wireguard'] = 'WireGuard';
7652
	}
7653

    
7654
	return($iflist);
7655
}
7656

    
7657
function is_pseudo_interface($inf, $tap=true) {
7658
	global $config;
7659
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe', 'wg');
7660
	foreach ($psifs as $pif) {
7661
		if (substr($inf, 0, strlen($pif)) == $pif) {
7662
			if (($pif == 'ovpn') && $tap) {
7663
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7664
				$type = ($m[1] == 'c') ? 'client' : 'server';
7665
				foreach ($config['openvpn']['openvpn-'.$type] as $ovpn) {
7666
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7667
						return false;
7668
					} elseif ($ovpn['vpnid'] == $m[2]) {
7669
						return true;
7670
					}
7671
				}
7672
			} else {
7673
				return true;
7674
			}
7675
		}
7676
	}
7677
	return false;
7678
}
7679

    
7680
function is_stf_interface($inf) {
7681
	global $config;
7682

    
7683
	if (is_array($config['interfaces'][$inf]) &&
7684
	    (($config['interfaces'][$inf]['ipaddrv6'] == '6rd') ||
7685
	    ($config['interfaces'][$inf]['ipaddrv6'] == '6to4'))) {
7686
	    return true;
7687
	}
7688

    
7689
	return false;
7690
}
7691

    
7692
?>
(22-22/61)