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-2022 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("config.lib.inc");
30
require_once("globals.inc");
31
require_once("util.inc");
32
require_once("gwlb.inc");
33
require_once("ipsec.inc");
34
require_once("vpn.inc");
35
require_once("Net/IPv6.php");
36

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

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

    
52
	if (empty($value)) {
53
		return false;
54
	}
55

    
56
	$list = explode(',', $value);
57

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

    
64
	return true;
65
}
66

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

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

    
78
	return $interface_arr_cache;
79
}
80

    
81
/*
82
 * does_interface_exist($interface): return true or false if a interface is
83
 * detected.
84
 */
85
function does_interface_exist($interface, $flush = false) {
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
	if (!$vip) {
104
		return false;
105
	}
106

    
107

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

    
123
	$ifacedata = pfSense_getall_interface_addresses($realif);
124

    
125
	if (is_subnetv6("{$vip['subnet']}/{$vip['subnet_bits']}")) {
126
		$comparevip = text_to_compressed_ip6($vip['subnet']);
127
		if (is_linklocal($vip['subnet'])) {
128
			$comparevip .= "%{$realif}";
129
		}
130
		$comparevip .= "/{$vip['subnet_bits']}";
131
	} else {
132
		$comparevip = "{$vip['subnet']}/{$vip['subnet_bits']}";
133
	}
134

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

    
141
	return false;
142
}
143

    
144
function interfaces_loopback_configure() {
145
	if (platform_booting()) {
146
		echo gettext("Configuring loopback interface...");
147
		mute_kernel_msgs();
148
	}
149
	pfSense_interface_setaddress("lo0", "127.0.0.1");
150
	interfaces_bring_up("lo0");
151
	if (platform_booting()) {
152
		unmute_kernel_msgs();
153
		echo gettext("done.") . "\n";
154
	}
155
	return 0;
156
}
157

    
158
function vlan_valid_tag($tag = NULL) {
159

    
160
	if ($tag == NULL || empty($tag) ||
161
	    !is_numericint($tag) || intval($tag) < 1 || intval($tag) > 4094) {
162
		return (false);
163
	}
164
	return (true);
165
}
166

    
167
function qinq_inuse($qinq = NULL, $inqtag = NULL) {
168
	if ($qinq == NULL || $inqtag == NULL ||
169
	    !is_array($qinq) || !vlan_valid_tag($inqtag)) {
170
		return (false);
171
	}
172

    
173
        $iflist = get_configured_interface_list(true);
174
        foreach ($iflist as $if) {
175
                if (config_get_path("interfaces/{$if}/if") == qinq_interface($qinq, $inqtag)) {
176
                        return (true);
177
                }
178
        }
179

    
180
        return (false);
181
}
182

    
183
function qinq_interface($qinq = NULL, $inqtag = NULL) {
184

    
185
	if ($qinq == NULL || $inqtag == NULL || !is_array($qinq) ||
186
	    !isset($qinq['if']) || !isset($qinq['tag']) ||
187
	    !vlan_valid_tag($qinq['tag']) || !vlan_valid_tag($inqtag)) {
188
		return (NULL);
189
	}
190
	return ("{$qinq['if']}.{$qinq['tag']}.{$inqtag}");
191
}
192

    
193
function interface_is_qinq($if = NULL) {
194
	if (!$if) {
195
		return (NULL);
196
	}
197

    
198
	/* Check basic format. */
199
	list($qinqif, $vlantag, $inqtag) = explode(".", $if);
200
	if (empty($qinqif) || empty($vlantag) || empty($inqtag) ||
201
	    !vlan_valid_tag($vlantag) || !vlan_valid_tag($inqtag)) {
202
		return (NULL);
203
	}
204

    
205
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
206
		if ("{$qinqif}.{$vlantag}" != $qinq['vlanif']) {
207
			continue;
208
		}
209
		if (empty($qinq['members'])) {
210
			continue;
211
		}
212
		foreach (explode(" ", $qinq['members']) as $tag) {
213
			if ($if == qinq_interface($qinq, $tag)) {
214
				return ($qinq);
215
			}
216
		}
217
	}
218

    
219
	return (NULL);
220
}
221

    
222
function vlan_inuse($vlan) {
223
	if ($vlan == NULL || !is_array($vlan)) {
224
		return (false);
225
	}
226

    
227
	$iflist = get_configured_interface_list(true);
228
	foreach ($iflist as $if) {
229
		if (config_get_path("interfaces/{$if}/if") == $vlan['vlanif']) {
230
			return (true);
231
		}
232
	}
233

    
234
	return (false);
235
}
236

    
237
function interface_is_vlan($if = NULL) {
238
	if ($if == NULL || empty($if) || is_array($if)) {
239
		return (NULL);
240
	}
241

    
242
	/* Check basic format. */
243
	$items = explode(".", $if, 2);
244
	$vlanif = array_shift($items);
245
	$vlantag = array_shift($items);
246
	if (empty($vlanif) || empty($vlantag) || !vlan_valid_tag($vlantag)) {
247
		return (NULL);
248
	}
249

    
250
	/* Find the VLAN interface. */
251
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
252
		if ($if == $vlan['vlanif']) {
253
			return ($vlan);
254
		}
255
	}
256

    
257
	/* Check for the first level tag in QinQ interfaces. */
258
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
259
		if ($if == $qinq['vlanif']) {
260
			return ($qinq);
261
		}
262
	}
263

    
264
	return (NULL);
265
}
266

    
267
function vlan_interface($vlan = NULL) {
268
	if ($vlan == NULL || !is_array($vlan) || !isset($vlan['if']) ||
269
	    !isset($vlan['tag']) || !vlan_valid_tag($vlan['tag'])) {
270
		return (NULL);
271
	}
272
	return ("{$vlan['if']}.{$vlan['tag']}");
273
}
274

    
275
function interface_set_macaddr($interface, $mac_addr) {
276
	if (empty($mac_addr) || !is_macaddr($mac_addr)) {
277
		return;
278
	}
279

    
280
	$current_mac = get_interface_mac($interface);
281

    
282
	/*
283
	 * Don't try to reapply the MAC if it's already applied.
284
	 * When ifconfig link is used, it cycles the interface down/up, which
285
	 * triggers the interface config again, which attempts to apply the
286
	 * MAC again, which cycles the link again...
287
	 */
288
	if ($mac_addr != $current_mac) {
289
		mwexec("/sbin/ifconfig " . escapeshellarg($interface) .
290
		    " link " . escapeshellarg($mac_addr));
291
	}
292
}
293

    
294
function interface_is_parent($if, $parent_check) {
295

    
296
	$parent_array = get_parent_interface($if);
297
	if (count($parent_array) > 1) {
298
		$parent = $parent_array;
299
	} else {
300
		$parent = $parent_array[0];
301
	}
302
	if (is_array($parent)) {
303
		foreach ($parent as $parentif) {
304
			if (strcasecmp($parent_check, $parentif) == 0) {
305
				return (TRUE);
306
			}
307
		}
308
	} else {
309
		$realif = get_real_interface($parent);
310
		if (strcasecmp($parent_check, $realif) == 0) {
311
			return (TRUE);
312
		}
313
	}
314
	return (FALSE);
315
}
316

    
317
function interface_has_clones($if) {
318
	/* Check LAGGs. */
319
	foreach (config_get_path('laggs/lagg', []) as $lagg) {
320
		if (interface_is_parent($lagg['laggif'], $if)) {
321
			return (TRUE);
322
		}
323
	}
324
	/* Check VLANs. */
325
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
326
		if (interface_is_parent($vlan['if'], $if)) {
327
			return (TRUE);
328
		}
329
	}
330
	/* Check bridges. */
331
	foreach (config_get_path('bridges/bridged', []) as $bridge) {
332
		$members = explode(',', $bridge['members']);
333
		foreach ($members as $member) {
334
			if (interface_is_parent($member, $if)) {
335
				return (TRUE);
336
			}
337
		}
338
	}
339

    
340
	return (FALSE);
341
}
342

    
343
function interfaces_vlan_configure($parentif = "") {
344
	$dhcp6c_list = array();
345

    
346
	$vlans = config_get_path('vlans/vlan');
347
	if (is_array($vlans) && count($vlans)) {
348
		if (platform_booting()) {
349
			echo gettext("Configuring VLAN interfaces...");
350
		}
351
		foreach ($vlans as $vlan) {
352
			if (empty($vlan['vlanif'])) {
353
				$vlan['vlanif'] = vlan_interface($vlan);
354
			}
355
			if (!empty($parentif) && ($parentif != $vlan['if'])) {
356
				continue;
357
			}
358
			/* configure dhcp6 enabled VLAN interfaces later
359
			 * see https://redmine.pfsense.org/issues/3965 */
360
			$if = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
361
			if (config_get_path("interfaces/{$if}/ipaddrv6", "") == "dhcp6") {
362
				$dhcp6c_list[$if] = $vlan;
363
				continue;
364
			}
365

    
366
			/* XXX: Maybe we should report any errors?! */
367
			interface_vlan_configure($vlan, false);
368
		}
369
		foreach ($dhcp6c_list as $if => $vlan) {
370
			interface_vlan_configure($vlan, false);
371
		}
372
		/* Invalidate cache */
373
		get_interface_arr(true);
374
		if (platform_booting()) {
375
			echo gettext("done.") . "\n";
376
		}
377
	}
378
}
379

    
380
function interface_vlan_configure(&$vlan, $flush = true) {
381
	if (!is_array($vlan)) {
382
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
383
		return(NULL);
384
	}
385
	$if = $vlan['if'];
386
	if (empty($if)) {
387
		log_error(gettext("interface_vlan_configure called with if undefined."));
388
		return(NULL);
389
	}
390

    
391
	$vlanif = empty($vlan['vlanif']) ? vlan_interface($vlan) : $vlan['vlanif'];
392
	if ($vlanif == NULL) {
393
		log_error(gettext("vlan_interface called with if undefined var."));
394
		return(NULL);
395
	}
396
	$tag = $vlan['tag'];
397
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
398

    
399
	/* make sure the parent interface is up */
400
	interfaces_bring_up($if);
401
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
402
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
403

    
404
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
405
		pfSense_interface_destroy($vlanif);
406
	}
407

    
408
	$tmpvlanif = pfSense_interface_create2("vlan");
409
	pfSense_interface_rename($tmpvlanif, $vlanif);
410
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
411

    
412
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
413

    
414
	interfaces_bring_up($vlanif);
415

    
416
	/* invalidate interface cache */
417
	if ($flush) {
418
		get_interface_arr(true);
419
	}
420

    
421
	/* configure interface if assigned */
422
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
423
	if ($assignedif) {
424
		if (config_path_enabled("interfaces/{$assignedif}")) {
425
			interface_configure($assignedif, true);
426
		}
427
	}
428

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

    
432
	if (interface_vlan_mtu_configured($vlanif)) {
433
		set_interface_mtu($vlanif, interface_vlan_mtu_configured($vlanif));
434
	}
435

    
436
	return $vlanif;
437
}
438

    
439
/*
440
 * reconfigure VLAN childs interfaces after MTU changes, see
441
 * https://redmine.pfsense.org/issues/11035
442
 */
443
function interfaces_vlan_configure_mtu($parentif = "") {
444
	init_config_arr(array('ppps', 'ppp'));
445
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
446
		if ($parentif != $vlan['if']) {
447
			continue;
448
		}
449
		if (interface_vlan_mtu_configured($vlan['vlanif'])) {
450
		       set_interface_mtu($vlan['vlanif'],
451
			   interface_vlan_mtu_configured($vlan['vlanif']));
452
		}
453
		if (empty(config_get_path('ppps/ppp'))) {
454
			continue;
455
		}
456
		// PPP interfaces must be restarted to adjust MTU changes
457
		foreach (config_get_path('ppps/ppp') as $ppp) {
458
			$ports = explode(',', $ppp['ports']);
459
			foreach ($ports as $port) {
460
				if ($port != $vlan['vlanif']) {
461
					continue;
462
				}
463
				$confif = convert_real_interface_to_friendly_interface_name($ppp['if']);
464
				interface_configure($confif);
465
			}
466
		}
467
	}
468
}
469

    
470
function interface_qinq_configure(&$qinq, $flush = true) {
471
	global $g;
472

    
473
	if (!is_array($qinq)) {
474
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
475
		return;
476
	}
477

    
478
	$qinqif = $qinq['if'];
479
	if (empty($qinqif)) {
480
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
481
		return;
482
	}
483

    
484
	if (!does_interface_exist($qinqif)) {
485
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
486
		return;
487
	}
488

    
489
	$vlanif = interface_vlan_configure($qinq);
490
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
491
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
492
		return;
493
	}
494

    
495
	$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
496

    
497
	/* make sure the parent is converted to ng_vlan(4) and is up */
498
	interfaces_bring_up($qinqif);
499

    
500
	$ngif = str_replace(".", "_", $vlanif);
501
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
502
		exec("/usr/sbin/ngctl shutdown {$ngif}qinq: > /dev/null 2>&1");
503
		exec("/usr/sbin/ngctl msg {$ngif}qinq: gettable > /dev/null 2>&1", $result);
504
		if (empty($result)) {
505
			fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
506
			fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
507
			fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
508
		}
509
	} else {
510
		fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
511
		fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
512
		fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
513
	}
514

    
515
	/* invalidate interface cache */
516
	if ($flush) {
517
		get_interface_arr(true);
518
	}
519

    
520
	if (interface_is_vlan($qinqif) == NULL) {
521
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
522
	}
523

    
524
	$macaddr = get_interface_mac($qinqif);
525
	if (!empty($qinq['members'])) {
526
		$qinqcmdbuf = "";
527
		$members = explode(" ", $qinq['members']);
528
		foreach ($members as $qtag) {
529
			$qinq2 = array();
530
			$qinq2['tag'] = $qtag;
531
			$qinq2['if'] = $vlanif;
532
			interface_qinq2_configure($qinq2, $qinqcmdbuf, $macaddr,
533
			    false);
534
			unset($qinq2);
535
		}
536
		if (strlen($qinqcmdbuf) > 0) {
537
			fwrite($fd, $qinqcmdbuf);
538
		}
539
	}
540

    
541
	fclose($fd);
542
	mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd > /dev/null 2>&1");
543

    
544
	interfaces_bring_up($qinqif);
545
	if (!empty($qinq['members'])) {
546
		$members = explode(" ", $qinq['members']);
547
		foreach ($members as $qtag) {
548
			interfaces_bring_up(qinq_interface($qinq, $qtag));
549
		}
550
	}
551

    
552
	return $vlanif;
553
}
554

    
555
function interfaces_qinq_configure($ovpn=false) {
556
	$qinqentry = config_get_path('qinqs/qinqentry');
557
	if (is_array($qinqentry) && count($qinqentry)) {
558
		if (platform_booting() && $ovpn) {
559
			echo gettext("Configuring OpenVPN QinQ interfaces...");
560
		} elseif (platform_booting()) {
561
			echo gettext("Configuring QinQ interfaces...");
562
		}
563
		foreach ($qinqentry as $qinq) {
564
			if (($ovpn && strstr($qinq['if'], "ovpn")) ||
565
			    (!$ovpn && !strstr($qinq['if'], "ovpn"))) {
566
				interface_qinq_configure($qinq, false);
567
			}
568
		}
569
		/* Invalidate cache */
570
		get_interface_arr(true);
571
		if (platform_booting()) {
572
			echo gettext("done.") . "\n";
573
		}
574
	}
575
}
576

    
577
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr, $flush = true) {
578
	if (!is_array($qinq)) {
579
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
580
		return;
581
	}
582

    
583
	$if = $qinq['if'];
584
	if (empty($if)) {
585
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
586
		return;
587
	}
588
	$tag = $qinq['tag'];
589
	$vlanif = "{$if}.{$tag}";
590
	$ngif = str_replace(".", "_", $if);
591
	if (strlen($vlanif) > IF_NAMESIZE) {
592
		log_error(sprintf(gettext("interface_qinq2_configure interface name too big %s. (max. size: %d).%s"),
593
		    $vlanif, IF_NAMESIZE, "\n"));
594
		return;
595
	}
596

    
597
	exec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1");
598
	$cmdbuf .= "mkpeer {$ngif}qinq: eiface {$ngif}{$tag} ether\n";
599
	$cmdbuf .= "name {$ngif}qinq:{$ngif}{$tag} {$ngif}h{$tag}\n";
600
	$cmdbuf .= "msg {$ngif}qinq: addfilter { vlan={$tag} hook=\"{$ngif}{$tag}\" }\n";
601
	$cmdbuf .= "msg {$ngif}h{$tag}: setifname \"{$vlanif}\"\n";
602
	$cmdbuf .= "msg {$ngif}h{$tag}: set {$macaddr}\n";
603

    
604
	/* invalidate interface cache */
605
	if ($flush) {
606
		get_interface_arr(true);
607
	}
608

    
609
	return $vlanif;
610
}
611

    
612
function interfaces_create_wireless_clones() {
613
	$iflist = get_configured_interface_list();
614

    
615
	foreach ($iflist as $if) {
616
		$realif = config_get_path("interfaces/{$if}/if");
617
		if (!is_interface_wireless($realif)) {
618
			continue;
619
		}
620
		interface_wireless_clone(interface_get_wireless_clone($realif),
621
								 config_get_path("interfaces/{$if}"));
622
	}
623

    
624
	$wclone = config_get_path('wireless/clone');
625
	if (is_array($wclone) && count($wclone)) {
626
		if (platform_booting()) {
627
			echo gettext("Creating wireless clone interfaces...");
628
		}
629
		/* Invalidate cache */
630
		get_interface_arr(true);
631
		foreach ($wclone as $clone) {
632
			if (empty($clone['cloneif'])) {
633
				continue;
634
			}
635
			if (does_interface_exist($clone['cloneif'])) {
636
				continue;
637
			}
638
			/* XXX: Maybe we should report any errors?! */
639
			interface_wireless_clone($clone['cloneif'], $clone);
640
		}
641
		if (platform_booting()) {
642
			echo gettext("done.") . "\n";
643
		}
644
	}
645
}
646

    
647
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
648
	$bridged = config_get_path('bridges/bridged');
649
	if (!is_array($bridged) || !count($bridged)) {
650
		return;
651
	}
652

    
653
	$i = 0;
654
	foreach ($bridged as $bridge) {
655
		if (empty($bridge['bridgeif'])) {
656
			$bridge['bridgeif'] = "bridge{$i}";
657
		}
658
		if (!empty($realif) && ($realif != $bridge['bridgeif'])) {
659
			continue;
660
		}
661
		$ifname = false;
662
		foreach (config_get_path('interfaces', []) as $intname => $intpar) {
663
			if ($intpar['if'] == $bridge['bridgeif']) {
664
				$ifname = $intname;
665
				break;
666
			}
667
		}
668

    
669
		if ($ifname && (config_get_path("interfaces/{$ifname}/ipaddrv6", "") == "track6")) {
670
			if ($checkmember == 1) {
671
				continue;
672
			} else {
673
				$checkmember = 0;
674
			}
675
		} elseif (($checkmember == 2) && !$ifname) {
676
			continue;
677
		}
678

    
679
		/* XXX: Maybe we should report any errors?! */
680
		interface_bridge_configure($bridge, $checkmember, false);
681
		$i++;
682
	}
683

    
684
	/* Invalidate cache */
685
	get_interface_arr(true);
686
}
687

    
688
function interface_bridge_configure(&$bridge, $checkmember = 0, $flush = true) {
689
	if (!is_array($bridge)) {
690
		return;
691
	}
692

    
693
	if (empty($bridge['members'])) {
694
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
695
		return;
696
	}
697

    
698
	$members = explode(',', $bridge['members']);
699
	if (!count($members)) {
700
		return;
701
	}
702

    
703
	/* Calculate smaller mtu and enforce it */
704
	$smallermtu = 0;
705
	$foundgif = false;
706
	foreach ($members as $member) {
707
		$realif = get_real_interface($member);
708
		$mtu = get_interface_mtu($realif);
709
		if (substr($realif, 0, 3) == "gif") {
710
			$foundgif = true;
711
			if ($checkmember == 1) {
712
				return;
713
			}
714
			if ($mtu <= 1500) {
715
				continue;
716
			}
717
		}
718
		if ($smallermtu == 0 && !empty($mtu)) {
719
			$smallermtu = $mtu;
720
		} elseif (!empty($mtu) && $mtu < $smallermtu) {
721
			$smallermtu = $mtu;
722
		}
723
	}
724
	if ($foundgif == false && $checkmember == 2) {
725
		return;
726
	}
727

    
728
	/* Just in case anything is not working well */
729
	if ($smallermtu == 0) {
730
		$smallermtu = 1500;
731
	}
732

    
733
	if (!empty($bridge['bridgeif'])) {
734
		pfSense_interface_destroy($bridge['bridgeif']);
735
		pfSense_interface_create2($bridge['bridgeif']);
736
		$bridgeif = escapeshellarg($bridge['bridgeif']);
737
	} else {
738
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
739
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
740
		$bridgeif = pfSense_interface_create2("bridge");
741
		$bridge['bridgeif'] = $bridgeif;
742
	}
743

    
744
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
745
	if ($bridgemtu > $smallermtu) {
746
		$smallermtu = $bridgemtu;
747
	}
748

    
749
	$checklist = get_configured_interface_list();
750

    
751
	/* Add interfaces to bridge */
752
	foreach ($members as $member) {
753
		if (empty($checklist[$member])) {
754
			continue;
755
		}
756
		$realif = get_real_interface($member);
757
		if (!$realif) {
758
			log_error(gettext("realif not defined in interfaces bridge - up"));
759
			continue;
760
		}
761
		/* make sure the parent interface is up */
762
		pfSense_interface_mtu($realif, $smallermtu);
763
		interfaces_bring_up($realif);
764
		enable_hardware_offloading($member);
765
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
766
	}
767

    
768
	if (isset($bridge['enablestp'])) {
769
		interface_bridge_configure_stp($bridge);
770
	}
771

    
772
	interface_bridge_configure_advanced($bridge);
773

    
774
	interface_bridge_configure_ip6linklocal($bridge);
775

    
776
	if ($flush) {
777
		get_interface_arr(true);
778
	}
779

    
780
	if ($bridge['bridgeif']) {
781
		interfaces_bring_up($bridge['bridgeif']);
782
	} else {
783
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
784
	}
785
}
786

    
787
function interface_bridge_configure_stp($bridge) {
788
	if (isset($bridge['enablestp'])) {
789
		$bridgeif = trim($bridge['bridgeif']);
790
		/* configure spanning tree proto */
791
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
792

    
793
		if (!empty($bridge['stp'])) {
794
			$stpifs = explode(',', $bridge['stp']);
795
			foreach ($stpifs as $stpif) {
796
				$realif = get_real_interface($stpif);
797
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
798
			}
799
		}
800
		if (!empty($bridge['maxage'])) {
801
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
802
		}
803
		if (!empty($bridge['fwdelay'])) {
804
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
805
		}
806
		if (!empty($bridge['hellotime'])) {
807
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
808
		}
809
		if (!empty($bridge['priority'])) {
810
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
811
		}
812
		if (!empty($bridge['holdcnt'])) {
813
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
814
		}
815
		if (!empty($bridge['ifpriority'])) {
816
			$pconfig = explode(",", $bridge['ifpriority']);
817
			$ifpriority = array();
818
			foreach ($pconfig as $cfg) {
819
				$embcfg = explode_assoc(":", $cfg);
820
				foreach ($embcfg as $key => $value) {
821
					$ifpriority[$key] = $value;
822
				}
823
			}
824
			foreach ($ifpriority as $key => $value) {
825
				$realif = get_real_interface($key);
826
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
827
			}
828
		}
829
		if (!empty($bridge['ifpathcost'])) {
830
			$pconfig = explode(",", $bridge['ifpathcost']);
831
			$ifpathcost = array();
832
			foreach ($pconfig as $cfg) {
833
				$embcfg = explode_assoc(":", $cfg);
834
				foreach ($embcfg as $key => $value) {
835
					$ifpathcost[$key] = $value;
836
				}
837
			}
838
			foreach ($ifpathcost as $key => $value) {
839
				$realif = get_real_interface($key);
840
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
841
			}
842
		}
843
	}
844
}
845

    
846
function interface_bridge_configure_advanced($bridge) {
847
	$bridgeif = trim($bridge['bridgeif']);
848

    
849
	if ($bridge['maxaddr'] <> "") {
850
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
851
	}
852
	if ($bridge['timeout'] <> "") {
853
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
854
	}
855
	if (!empty($bridge['span'])) {
856
		$spanifs = explode(",", $bridge['span']);
857
		foreach ($spanifs as $spanif) {
858
			$realif = get_real_interface($spanif);
859
			mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
860
		}
861
	}
862
	if (!empty($bridge['edge'])) {
863
		$edgeifs = explode(',', $bridge['edge']);
864
		foreach ($edgeifs as $edgeif) {
865
			$realif = get_real_interface($edgeif);
866
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
867
		}
868
	}
869
	if (!empty($bridge['autoedge'])) {
870
		$edgeifs = explode(',', $bridge['autoedge']);
871
		foreach ($edgeifs as $edgeif) {
872
			$realif = get_real_interface($edgeif);
873
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
874
		}
875
	}
876
	if (!empty($bridge['ptp'])) {
877
		$ptpifs = explode(',', $bridge['ptp']);
878
		foreach ($ptpifs as $ptpif) {
879
			$realif = get_real_interface($ptpif);
880
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
881
		}
882
	}
883
	if (!empty($bridge['autoptp'])) {
884
		$ptpifs = explode(',', $bridge['autoptp']);
885
		foreach ($ptpifs as $ptpif) {
886
			$realif = get_real_interface($ptpif);
887
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
888
		}
889
	}
890
	if (!empty($bridge['static'])) {
891
		$stickyifs = explode(',', $bridge['static']);
892
		foreach ($stickyifs as $stickyif) {
893
			$realif = get_real_interface($stickyif);
894
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
895
		}
896
	}
897
	if (!empty($bridge['private'])) {
898
		$privateifs = explode(',', $bridge['private']);
899
		foreach ($privateifs as $privateif) {
900
			$realif = get_real_interface($privateif);
901
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
902
		}
903
	}
904
}
905

    
906
function interface_bridge_configure_ip6linklocal($bridge) {
907
	$bridgeif = trim($bridge['bridgeif']);
908

    
909
	$members = explode(',', $bridge['members']);
910
	if (!count($members)) {
911
		return;
912
	}
913

    
914
	$auto_linklocal = isset($bridge['ip6linklocal']);
915
	$bridgeop = $auto_linklocal ? '' : '-';
916
	$memberop = $auto_linklocal ? '-' : '';
917

    
918
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
919
	foreach ($members as $member) {
920
		$realif = get_real_interface($member);
921
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
922
	}
923
}
924

    
925
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
926
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
927
		return;
928
	}
929

    
930
	if ($flagsapplied == false) {
931
		$mtu = get_interface_mtu($bridgeif);
932
		$mtum = get_interface_mtu($interface);
933
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
934
			pfSense_interface_mtu($interface, $mtu);
935
		}
936

    
937
		hardware_offloading_applyflags($interface);
938
		interfaces_bring_up($interface);
939
	}
940

    
941
	pfSense_bridge_add_member($bridgeif, $interface);
942
	$bridged = config_get_path('bridges/bridged');
943
	if (is_array($bridged)) {
944
		foreach ($bridged as $bridge) {
945
			if ($bridgeif == $bridge['bridgeif']) {
946
				interface_bridge_configure_stp($bridge);
947
				interface_bridge_configure_advanced($bridge);
948
			}
949
		}
950
	}
951
}
952

    
953
function interfaces_lagg_configure($realif = "") {
954
	$i = 0;
955
	$laggs = config_get_path('laggs/lagg');
956
	if (is_array($laggs) && count($laggs)) {
957
		if (platform_booting()) {
958
			echo gettext("Configuring LAGG interfaces...");
959
		}
960
		foreach ($laggs as $lagg) {
961
			if (empty($lagg['laggif'])) {
962
				$lagg['laggif'] = "lagg{$i}";
963
			}
964
			if (!empty($realif) && $realif != $lagg['laggif']) {
965
				continue;
966
			}
967
			/* XXX: Maybe we should report any errors?! */
968
			interface_lagg_configure($lagg, false);
969
			$i++;
970
		}
971
		/* Invalidate cache */
972
		get_interface_arr(true);
973
		if (platform_booting()) {
974
			echo gettext("done.") . "\n";
975
		}
976
	}
977
}
978

    
979
function interface_lagg_configure($lagg, $flush = true) {
980
	if (!is_array($lagg)) {
981
		return -1;
982
	}
983

    
984
	$members = explode(',', $lagg['members']);
985
	if (!count($members)) {
986
		return -1;
987
	}
988

    
989
	if (platform_booting() || !(empty($lagg['laggif']))) {
990
		pfSense_interface_destroy($lagg['laggif']);
991
		pfSense_interface_create2($lagg['laggif']);
992
		$laggif = $lagg['laggif'];
993
	} else {
994
		$laggif = pfSense_interface_create2("lagg");
995
	}
996

    
997
	/* Check if MTU was defined for this lagg interface */
998
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
999
	if ($lagg_mtu == 0) {
1000
		foreach (config_get_path('interfaces', []) as $tmpinterface) {
1001
			if ($tmpinterface['if'] == $lagg['laggif'] &&
1002
			    !empty($tmpinterface['mtu'])) {
1003
				$lagg_mtu = $tmpinterface['mtu'];
1004
				break;
1005
			}
1006
		}
1007
	}
1008

    
1009
	/* Just in case anything is not working well */
1010
	if ($lagg_mtu == 0) {
1011
		$lagg_mtu = 1500;
1012
	}
1013

    
1014
	// put failover master interface on top of list
1015
	if (($lagg['proto'] == 'failover') && isset($lagg['failovermaster']) &&
1016
	    ($lagg['failovermaster'] != 'auto')) {
1017
		unset($members[array_search($lagg['failovermaster'], $members)]);
1018
		$members = array_merge(array($lagg['failovermaster']), $members);
1019
	}
1020

    
1021
	if (($lagg['proto'] == 'lacp') && isset($lagg['lacptimeout']) &&
1022
	    ($lagg['lacptimeout'] != 'slow')) {
1023
		$lacptimeout = 'lacp_fast_timeout';
1024
	} else {
1025
		$lacptimeout = '';
1026
	}
1027

    
1028
	if ((($lagg['proto'] == 'lacp') || ($lagg['proto'] == 'loadbalance')) &&
1029
	    isset($lagg['lagghash']) && !empty($lagg['lagghash'])) {
1030
		$lagghash = 'lagghash ' . escapeshellarg($lagg['lagghash']);
1031
	} else {
1032
		$lagghash = '';
1033
	}
1034

    
1035
	foreach ($members as $member) {
1036
		if (!does_interface_exist($member)) {
1037
			continue;
1038
		}
1039

    
1040
		/* make sure the parent interface is up */
1041
		pfSense_interface_mtu($member, $lagg_mtu);
1042
		interfaces_bring_up($member);
1043
		hardware_offloading_applyflags($member);
1044

    
1045
		// Ensure there are no nulls in these values. It upsets escapeshellarg()
1046
		$laggif = str_replace("\0", "", $laggif);
1047
		$member = str_replace("\0", "", $member);
1048
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
1049
	}
1050

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

    
1053
	if ($flush) {
1054
		get_interface_arr(true);
1055
	}
1056

    
1057
	interfaces_bring_up($laggif);
1058

    
1059
	return $laggif;
1060
}
1061

    
1062
/* NOTE: $grekey is not used but useful for passing this function to array_walk. */
1063
function interface_gre_configure(&$gre, $grekey = "", $flush = true) {
1064
	global $g;
1065

    
1066
	if (!is_array($gre)) {
1067
		return -1;
1068
	}
1069

    
1070
	$realif = convert_friendly_interface_to_real_interface_name($gre['if']);
1071
	if (!interface_is_vlan($realif)) {
1072
		$realif = get_real_interface($gre['if']);
1073
	}
1074
	$realifip = get_interface_ip($gre['if']);
1075
	$realifip6 = get_interface_ipv6($gre['if']);
1076

    
1077
	/* do not run ifconfig without correct $realifip */
1078
	if ((!$realifip && is_ipaddrv4($gre['remote-addr'])) || 
1079
	    (!$realifip6 && is_ipaddrv6($gre['remote-addr']))) {
1080
		return -1;
1081
	}
1082

    
1083
	/* make sure the parent interface is up */
1084
	interfaces_bring_up($realif);
1085

    
1086
	if (platform_booting() || !(empty($gre['greif']))) {
1087
		pfSense_interface_destroy($gre['greif']);
1088
		pfSense_interface_create2($gre['greif']);
1089
		$greif = $gre['greif'];
1090
	} else {
1091
		$greif = pfSense_interface_create2("gre");
1092
	}
1093

    
1094
	$tunnel_type = '';
1095
	if ((!empty($gre['tunnel-local-addr'])) || (!empty($gre['tunnel-remote-addr']))) {
1096
		$tunnel_type = 'v4';
1097
	}
1098
	if ((!empty($gre['tunnel-local-addr6'])) || (!empty($gre['tunnel-remote-addr6']))) {
1099
		$tunnel_type .= 'v6';
1100
	}
1101

    
1102
	/* Do not change the order here for more see gre(4) NOTES section. */
1103
	if (is_ipaddrv6($gre['remote-addr'])) {
1104
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
1105
	} else {
1106
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
1107
	}
1108
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1109
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
1110
	}
1111
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1112
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1113
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr6']) . " " . escapeshellarg($gre['tunnel-remote-addr6']) . " prefixlen 128");
1114
	}
1115

    
1116
	$parentif = get_real_interface($gre['if']);
1117
	if ($parentif) {
1118
		interfaces_bring_up($parentif);
1119
	} else {
1120
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gre_configure()"));
1121
	}
1122

    
1123
	if (isset($gre['link1'])) {
1124
		if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1125
			mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1126
		}
1127
		if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1128
			mwexec("/sbin/route -6 add " . escapeshellarg($gre['tunnel-remote-addr6']) . "/" . escapeshellarg($gre['tunnel-remote-net6']) . " " . escapeshellarg($gre['tunnel-local-addr6']));
1129
		}
1130
	}
1131
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1132
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1133
		unlink_if_exists("{$g['tmp_path']}/{$greif}_router.last");
1134
	}
1135
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1136
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr6']);
1137
		unlink_if_exists("{$g['tmp_path']}/{$greif}_routerv6.last");
1138
	}
1139

    
1140
	if ($flush) {
1141
		get_interface_arr(true);
1142
	}
1143

    
1144
	interfaces_bring_up($greif);
1145

    
1146
	return $greif;
1147
}
1148

    
1149
function interface_is_type($if, $type) {
1150
	switch ($type) {
1151
		case "gre":
1152
			$list = 'gres';
1153
			$entry = 'gre';
1154
			$entif = 'greif';
1155
			break;
1156
		case "gif":
1157
			$list = 'gifs';
1158
			$entry = 'gif';
1159
			$entif = 'gifif';
1160
			break;
1161
		case "lagg":
1162
			$list = 'laggs';
1163
			$entry = 'lagg';
1164
			$entif = 'laggif';
1165
			break;
1166
		default:
1167
			break;
1168
	}
1169

    
1170
	$entries = config_get_path("{$list}/{$entry}");
1171
	if (!is_array($entries)) {
1172
		return (NULL);
1173
	}
1174

    
1175
	foreach ($entries as $ent) {
1176
		if ($ent[$entif] == $if) {
1177
			return ($ent);
1178
		}
1179
	}
1180
	return (NULL);
1181
}
1182

    
1183
function is_greipsec($if) {
1184
	if (ipsec_enabled()) {
1185
		foreach (config_get_path('gres/gre', []) as $gre) {
1186
			foreach (config_get_path('ipsec/phase1', []) as $ph1ent) {
1187
				foreach (config_get_path('ipsec/phase2', []) as $ph2ent) {
1188
					if (($ph1ent['ikeid'] == $ph2ent['ikeid']) && ($ph2ent['mode'] == 'transport') &&
1189
					    !isset($ph1ent['disabled']) && !isset($ph2ent['disabled']) &&
1190
					    ($ph1ent['interface'] == $gre['if']) && ($gre['greif'] == $if) &&
1191
					    ($ph1ent['remote-gateway'] == $gre['remote-addr'])) {
1192
						    return true;
1193
					}
1194
				}
1195
			}
1196
		}
1197
	}
1198
	return false;
1199
}
1200

    
1201
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1202
function interface_gif_configure(&$gif, $gifkey = "", $flush = true) {
1203
	if (!is_array($gif)) {
1204
		return -1;
1205
	}
1206

    
1207
	$realif = convert_friendly_interface_to_real_interface_name($gif['if']);
1208
	if (!interface_is_vlan($realif)) {
1209
		$realif = get_real_interface($gif['if']);
1210
	}
1211
	$ipaddr = get_interface_ip($gif['if']);
1212

    
1213
	if (is_ipaddrv4($gif['remote-addr'])) {
1214
		if (is_ipaddrv4($ipaddr)) {
1215
			$realifip = $ipaddr;
1216
		} else {
1217
			$realifip = get_interface_ip($gif['if']);
1218
		}
1219
		$realifgw = get_interface_gateway($gif['if']);
1220
	} elseif (is_ipaddrv6($gif['remote-addr'])) {
1221
		if (is_ipaddrv6($ipaddr)) {
1222
			$realifip = $ipaddr;
1223
		} else {
1224
			$realifip = get_interface_ipv6($gif['if']);
1225
		}
1226
		$realifgw = get_interface_gateway_v6($gif['if']);
1227
	}
1228

    
1229
	/* do not run ifconfig without correct $realifip */
1230
	if ((!is_ipaddrv4($realifip) && is_ipaddrv4($gif['remote-addr'])) || 
1231
	    (!is_ipaddrv6($realifip) && is_ipaddrv6($gif['remote-addr']))) {
1232
		return -1;
1233
	}
1234

    
1235
	/* make sure the parent interface is up */
1236
	$parentif = get_real_interface($gif['if']);
1237
	if ($parentif) {
1238
		interfaces_bring_up($parentif);
1239
	} else {
1240
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gif_configure()"));
1241
	}
1242

    
1243
	if (platform_booting() || !(empty($gif['gifif']))) {
1244
		pfSense_interface_destroy($gif['gifif']);
1245
		pfSense_interface_create2($gif['gifif']);
1246
		$gifif = $gif['gifif'];
1247
	} else {
1248
		$gifif = pfSense_interface_create2("gif");
1249
	}
1250

    
1251
	/* Do not change the order here for more see gif(4) NOTES section. */
1252
	if (is_ipaddrv6($gif['remote-addr'])) {
1253
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1254
	} else {
1255
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1256
	}
1257
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1258
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1259
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1260
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1261
	} else {
1262
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1263
	}
1264
	if (isset($gif['link1'])) {
1265
		pfSense_interface_flags($gifif, IFF_LINK1);
1266
	}
1267
	if (isset($gif['link2'])) {
1268
		pfSense_interface_flags($gifif, IFF_LINK2);
1269
	}
1270
	if ($gifif) {
1271
		interfaces_bring_up($gifif);
1272
		$gifmtu = "";
1273
		$currentgifmtu = get_interface_mtu($gifif);
1274
		foreach (config_get_path('interfaces', []) as $tmpinterface) {
1275
			if ($tmpinterface['if'] == $gifif) {
1276
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1277
					$gifmtu = $tmpinterface['mtu'];
1278
				}
1279
			}
1280
		}
1281
		if (is_numericint($gifmtu)) {
1282
			if ($gifmtu != $currentgifmtu) {
1283
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1284
			}
1285
		}
1286
	} else {
1287
		log_error(gettext("could not bring gifif up -- variable not defined"));
1288
	}
1289

    
1290
	if (!platform_booting()) {
1291
		$iflist = get_configured_interface_list();
1292
		foreach ($iflist as $ifname) {
1293
			$if = config_get_path("interfaces/{$ifname}/if", "");
1294
			if ($if == $gifif) {
1295
				if (get_interface_gateway($ifname)) {
1296
					system_routing_configure($ifname);
1297
					break;
1298
				}
1299
				if (get_interface_gateway_v6($ifname)) {
1300
					system_routing_configure($ifname);
1301
					break;
1302
				}
1303
			}
1304
		}
1305
	}
1306

    
1307

    
1308
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1309
		file_put_contents("{$g['tmp_path']}/{$gifif}_router",
1310
		    $gif['tunnel-remote-addr']);
1311
		unlink_if_exists("{$g['tmp_path']}/{$gifif}_router.last");
1312
	} elseif (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1313
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6",
1314
		    $gif['tunnel-remote-addr']);
1315
		unlink_if_exists("{$g['tmp_path']}/{$gifif}_routerv6.last");
1316
	}
1317

    
1318
	route_add_or_change($gif['remote-addr'], $realifgw);
1319

    
1320
	if ($flush) {
1321
		get_interface_arr(true);
1322
	}
1323

    
1324
	interfaces_bring_up($gifif);
1325

    
1326
	return $gifif;
1327
}
1328

    
1329
function interfaces_tunnel_configure($checkparent = 0, $realif = "", $type = "") {
1330
	if (!in_array($type, array('gre', 'gif'))) {
1331
		return;
1332
	}
1333

    
1334
	$tuns = config_get_path("{$type}s/{$type}");
1335
	if (!is_array($tuns) || !count($tuns)) {
1336
		return;
1337
	}
1338

    
1339
	foreach ($tuns as $i => $tunnel) {
1340
		if (empty($tunnel["{$type}if"])) {
1341
			$tunnel["{$type}if"] = $type . $i;
1342
		}
1343
		if (!empty($realif) && $realif != $tunnel["{$type}if"]) {
1344
			continue;
1345
		}
1346

    
1347
		$ipaddrv6 = config_get_path("interfaces/{$tunnel}/if/ipaddrv6");
1348
		if ($checkparent == 1) {
1349
			if (substr($tunnel['if'], 0, 4) == '_vip') {
1350
				continue;
1351
			}
1352
			if (substr($tunnel['if'], 0, 5) == '_lloc') {
1353
				continue;
1354
			}
1355

    
1356
			if ($ipaddrv6 == "track6") {
1357
				continue;
1358
			}
1359
		} elseif ($checkparent == 2) {
1360
			if ((substr($tunnel['if'], 0, 4) != '_vip' &&
1361
			    substr($tunnel['if'], 0, 5) != '_lloc') &&
1362
				$ipaddrv6 != "track6") {
1363
				continue;
1364
			}
1365
		}
1366
		if ($type == 'gif') {
1367
			interface_gif_configure($tunnel, "", false);
1368
		} elseif ($type == 'gre') {
1369
			interface_gre_configure($tunnel, "", false);
1370
		}
1371
	}
1372

    
1373
	/* Invalidate cache */
1374
	get_interface_arr(true);
1375
}
1376

    
1377
/* Build a list of IPsec interfaces */
1378
function interface_ipsec_vti_list_p1($ph1ent) {
1379
	$iface_list = array();
1380

    
1381
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array(config_get_path('ipsec/phase2'))) {
1382
		return $iface_list;
1383
	}
1384

    
1385
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1386
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1387
		return $iface_list;
1388
	}
1389

    
1390
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1391
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1392
		foreach ($vtisubnet_spec as $vtisub) {
1393
			$iface_list[ipsec_get_ifname($ph1ent, $vtisub['reqid'])] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1394
		}
1395
	} else {
1396
		/* For IKEv2, only create one interface with additional addresses as aliases */
1397
		$iface_list[ipsec_get_ifname($ph1ent)] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1398
	}
1399
	return $iface_list;
1400
}
1401
function interface_ipsec_vti_list_all() {
1402
	$iface_list = array();
1403
	$phase1 = config_get_path('ipsec/phase1');
1404
	$phase2 = config_get_path('ipsec/phase2');
1405
	if (is_array($phase1) && is_array($phase2)) {
1406
		foreach ($phase1 as $ph1ent) {
1407
			if ($ph1ent['disabled']) {
1408
				continue;
1409
			}
1410
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1411
		}
1412
	}
1413
	return $iface_list;
1414
}
1415

    
1416
function is_interface_ipsec_vti_assigned($phase2) {
1417
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1418
	$vti_interface = null;
1419
	$vtisubnet_spec = ipsec_vti($phase1, true);
1420
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1421
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1422
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1423
			foreach ($vtisubnet_spec as $vtisub) {
1424
				/* Is this for this P2? */
1425
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1426
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1427
					$vti_interface = ipsec_get_ifname($phase1, $vtisub['reqid']);
1428
				}
1429
			}
1430
		} else {
1431
			$vti_interface = ipsec_get_ifname($phase1);
1432
		}
1433
	}
1434
	/* Check if this interface is assigned */
1435
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1436
}
1437
function interface_ipsec_vti_configure($ph1ent, $gateways_status = false) {
1438
	global $ipsec_reqid_base;
1439

    
1440
	if (empty($ph1ent) || !is_array($ph1ent) || empty(config_get_path('ipsec/phase2'))) {
1441
		return false;
1442
	}
1443

    
1444
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1445
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1446
		return false;
1447
	}
1448

    
1449
	$left_spec = ipsec_get_phase1_src($ph1ent, $gateways_status);
1450

    
1451
	/* Attempt to resolve the remote gateway if needed */
1452
	$right_spec = ipsec_get_phase1_dst($ph1ent);
1453
	if (empty($right_spec)) {
1454
		/* Far end cannot be resolved */
1455
		return false;
1456
	}
1457

    
1458
	$iface_addrs = array();
1459
	$reqids = array();
1460

    
1461
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1462
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1463
		/* Form a single interface for each P2 entry */
1464
		foreach ($vtisubnet_spec as $vtisub) {
1465
			$ipsecif = ipsec_get_ifname($ph1ent, $vtisub['reqid']);
1466
			if (!is_array($iface_addrs[$ipsecif])) {
1467
				$iface_addrs[$ipsecif] = array();
1468
			}
1469
			$vtisub['alias'] = "";
1470
			$iface_addrs[$ipsecif][] = $vtisub;
1471
			$reqids[$ipsecif] = $vtisub['reqid'];
1472
		}
1473
	} else {
1474
		/* For IKEv2, only create one interface with additional addresses as aliases */
1475
		$ipsecif = ipsec_get_ifname($ph1ent);
1476
		if (!is_array($iface_addrs[$ipsecif])) {
1477
			$iface_addrs[$ipsecif] = array();
1478
		}
1479
		$have_v4 = false;
1480
		$have_v6 = false;
1481
		foreach ($vtisubnet_spec as $vtisub) {
1482
			// Alias stuff
1483
			$vtisub['alias'] = "";
1484
			if (is_ipaddrv6($vtisub['left'])) {
1485
				if ($have_v6) {
1486
					$vtisub['alias'] = " alias";
1487
				}
1488
				$have_v6 = true;
1489
			} else {
1490
				if ($have_v4) {
1491
					$vtisub['alias'] = " alias";
1492
				}
1493
				$have_v4 = true;
1494
			}
1495
			$iface_addrs[$ipsecif][] = $vtisub;
1496
		}
1497
		/* IKEv2 w/o Split uses the reqid of the first P2 */
1498
		$reqids[$ipsecif] = $vtisubnet_spec[0]['reqid'];
1499
	}
1500

    
1501
	foreach ($iface_addrs as $ipsecif => $addrs) {
1502
		if (!is_array($addrs)) {
1503
			continue;
1504
		}
1505
		// Create IPsec interface
1506
		if (does_interface_exist($ipsecif)) {
1507
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy");
1508
		}
1509
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsec_reqid_base + $reqids[$ipsecif]));
1510

    
1511
		/* Apply the outer tunnel addresses to the interface */
1512
		$inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
1513
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} tunnel " . escapeshellarg($left_spec) . " " . escapeshellarg($right_spec) . " up");
1514

    
1515
		/* Loop through all of the addresses for this interface and apply them as needed */
1516
		foreach ($addrs as $addr) {
1517
			// apply interface addresses
1518
			if (is_v6($addr['left'])) {
1519
				$inet = "inet6";
1520
				$gwtype = "v6";
1521
				$right = '';
1522
			} else {
1523
				$inet = "inet";
1524
				$gwtype = "";
1525
				$right = escapeshellarg($addr['right']);
1526
			}
1527

    
1528
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . $right . $addr['alias']);
1529
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1530
			if (empty($addr['alias'])) {
1531
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1532
				unlink_if_exists("/tmp/{$ipsecif}_router{$gwtype}.last");
1533
			}
1534
		}
1535
		/* Check/set the MTU if the user configured a custom value.
1536
		 * https://redmine.pfsense.org/issues/9111 */
1537
		$currentvtimtu = get_interface_mtu($ipsecif);
1538
		foreach (config_get_path('interfaces', []) as $tmpinterface) {
1539
			if ($tmpinterface['if'] == $ipsecif) {
1540
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1541
					$vtimtu = $tmpinterface['mtu'];
1542
				}
1543
			}
1544
		}
1545
		if (is_numericint($vtimtu)) {
1546
			if ($vtimtu != $currentvtimtu) {
1547
				mwexec("/sbin/ifconfig {$ipsecif} mtu {$vtimtu}");
1548
			}
1549
		}
1550
		system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1551
	}
1552
	return true;
1553
}
1554

    
1555
function interfaces_ipsec_vti_configure($gateways_status = false) {
1556
	$bootmsg = false;
1557

    
1558
	/* Fetch gateway status if not passed */
1559
	if (!is_array($gateways_status)) {
1560
		$gateways_status = return_gateways_status(true);
1561
	}
1562
	foreach (config_get_path('ipsec/phase1', []) as $ph1ent) {
1563
		if ($ph1ent['disabled']) {
1564
			continue;
1565
		}
1566
		if (interface_ipsec_vti_configure($ph1ent, $gateways_status) &&
1567
			!$bootmsg && platform_booting()) {
1568
			echo gettext("Configuring IPsec VTI interfaces...");
1569
			$bootmsg = true;
1570
		}
1571
	}
1572
	if (platform_booting() && $bootmsg) {
1573
		echo gettext("done.") . "\n";
1574
	}
1575
}
1576

    
1577
function interfaces_configure() {
1578
	global $g;
1579

    
1580
	/* Set up our loopback interface */
1581
	interfaces_loopback_configure();
1582

    
1583
	/* create the unconfigured wireless clones */
1584
	interfaces_create_wireless_clones();
1585

    
1586
	/* set up LAGG virtual interfaces */
1587
	interfaces_lagg_configure();
1588

    
1589
	/* set up VLAN virtual interfaces */
1590
	interfaces_vlan_configure();
1591

    
1592
	interfaces_qinq_configure(false);
1593

    
1594
	$iflist = get_configured_interface_with_descr();
1595
	$delayed_list = array();
1596
	$bridge_list = array();
1597
	$track6_list = array();
1598
	$dhcp6c_list = array();
1599

    
1600
	/* This is needed to speedup interfaces on bootup. */
1601
	$reload = false;
1602
	if (!platform_booting()) {
1603
		$reload = true;
1604
	}
1605

    
1606
	foreach ($iflist as $if => $ifname) {
1607
		$realif = config_get_path("interfaces/{$if}/if","");
1608
		$ipaddrv6 = config_get_path("interfaces/{$if}/ipaddrv6", "");
1609
		if (strstr($realif, "bridge")) {
1610
			$bridge_list[$if] = $ifname;
1611
		} elseif (strstr($realif, "gre")) {
1612
			$delayed_list[$if] = $ifname;
1613
		} elseif (strstr($realif, "gif")) {
1614
			$delayed_list[$if] = $ifname;
1615
		} elseif (strstr($realif, "ovpn")) {
1616
			continue;
1617
		} elseif (strstr($realif, "ipsec")) {
1618
			continue;
1619
		} elseif ($ipaddrv6 == "track6") {
1620
			$track6_list[$if] = $ifname;
1621
		} else {
1622
			/* do not run dhcp6c if track interface does not exists
1623
			 * see https://redmine.pfsense.org/issues/3965
1624
			 * and https://redmine.pfsense.org/issues/11633 */ 
1625
			if ($ipaddrv6 == "dhcp6") {
1626
				$tr6list = link_interface_to_track6($if);
1627
				if (is_array($tr6list) && !empty($tr6list)) {
1628
					$dhcp6c_list[$if] = $ifname;
1629
					continue;
1630
				}
1631
			}
1632
			if (platform_booting()) {
1633
				printf(gettext("Configuring %s interface..."),
1634
				    $ifname);
1635
			}
1636

    
1637
			if ($g['debug']) {
1638
				log_error(sprintf(gettext("Configuring %s"),
1639
				    $ifname));
1640
			}
1641
			interface_configure($if, $reload);
1642
			if (platform_booting()) {
1643
				echo gettext("done.") . "\n";
1644
			}
1645
		}
1646
	}
1647

    
1648
	/*
1649
	 * NOTE: The following function parameter consists of
1650
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1651
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1652
	 */
1653

    
1654
	/* set up GRE virtual interfaces */
1655
	interfaces_tunnel_configure(1,'','gre');
1656

    
1657
	/* set up GIF virtual interfaces */
1658
	interfaces_tunnel_configure(1,'','gif');
1659

    
1660
	/* set up BRIDGE virtual interfaces */
1661
	interfaces_bridge_configure(1);
1662

    
1663
	foreach ($track6_list as $if => $ifname) {
1664
		if (platform_booting()) {
1665
			printf(gettext("Configuring %s interface..."), $ifname);
1666
		}
1667
		if ($g['debug']) {
1668
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1669
		}
1670

    
1671
		interface_configure($if, $reload);
1672

    
1673
		if (platform_booting()) {
1674
			echo gettext("done.") . "\n";
1675
		}
1676
	}
1677

    
1678
	/* bring up vip interfaces */
1679
	interfaces_vips_configure();
1680

    
1681
	/* set up GRE virtual interfaces */
1682
	interfaces_tunnel_configure(2,'','gre');
1683

    
1684
	/* set up GIF virtual interfaces */
1685
	interfaces_tunnel_configure(2,'','gif');
1686

    
1687
	foreach ($delayed_list as $if => $ifname) {
1688
		if (platform_booting()) {
1689
			printf(gettext("Configuring %s interface..."), $ifname);
1690
		}
1691
		if ($g['debug']) {
1692
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1693
		}
1694

    
1695
		interface_configure($if, $reload);
1696

    
1697
		if (platform_booting()) {
1698
			echo gettext("done.") . "\n";
1699
		}
1700
	}
1701

    
1702
	/* set up BRIDGE virtual interfaces */
1703
	interfaces_bridge_configure(2);
1704

    
1705
	foreach ($bridge_list as $if => $ifname) {
1706
		if (platform_booting()) {
1707
			printf(gettext("Configuring %s interface..."), $ifname);
1708
		}
1709
		if ($g['debug']) {
1710
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1711
		}
1712

    
1713
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1714
		// redmine #3997
1715
		interface_reconfigure($if, $reload);
1716
		interfaces_vips_configure($if);
1717

    
1718
		if (platform_booting()) {
1719
			echo gettext("done.") . "\n";
1720
		}
1721
	}
1722

    
1723
	foreach ($dhcp6c_list as $if => $ifname) {
1724
		if (platform_booting()) {
1725
			printf(gettext("Configuring %s interface..."), $ifname);
1726
		}
1727
		if ($g['debug']) {
1728
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1729
		}
1730

    
1731
		interface_configure($if, $reload);
1732

    
1733
		if (platform_booting()) {
1734
			echo gettext("done.") . "\n";
1735
		}
1736
	}
1737

    
1738
	/* set up IPsec VTI interfaces */
1739
	interfaces_ipsec_vti_configure();
1740

    
1741
	/* configure interface groups */
1742
	interfaces_group_setup();
1743

    
1744
	if (!platform_booting()) {
1745
		/* reconfigure static routes (kernel may have deleted them) */
1746
		system_routing_configure();
1747

    
1748
		/* reload IPsec tunnels */
1749
		ipsec_configure();
1750

    
1751
		/* restart dns servers (defering dhcpd reload) */
1752
		if (config_get_path('dnsmasq/enable')) {
1753
			services_dnsmasq_configure(false);
1754
		}
1755
		if (config_get_path('unbound/enable')) {
1756
			services_unbound_configure(false);
1757
		}
1758

    
1759
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1760
		services_dhcpd_configure();
1761
	}
1762

    
1763
	return 0;
1764
}
1765

    
1766
function interface_reconfigure($interface = "wan", $reloadall = false) {
1767
	interface_bring_down($interface);
1768
	interface_configure($interface, $reloadall);
1769
}
1770

    
1771
function interface_vip_bring_down($vip) {
1772
	global $g;
1773

    
1774
	$vipif = get_real_interface($vip['interface']);
1775
	switch ($vip['mode']) {
1776
		case "proxyarp":
1777
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1778
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1779
			}
1780
			break;
1781
		case "ipalias":
1782
			if (does_interface_exist($vipif)) {
1783
				if (is_ipaddrv6($vip['subnet'])) {
1784
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1785
				} else {
1786
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1787
				}
1788
			}
1789
			break;
1790
		case "carp":
1791
			/* XXX: Is enough to delete ip address? */
1792
			if (does_interface_exist($vipif)) {
1793
				if (is_ipaddrv6($vip['subnet'])) {
1794
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1795
				} else {
1796
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1797
				}
1798
			}
1799
			break;
1800
	}
1801
}
1802

    
1803
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1804
	global $g;
1805

    
1806
	$iface = config_get_path("interfaces/{$interface}");
1807
	if (!$iface) {
1808
		return;
1809
	}
1810

    
1811
	if ($g['debug']) {
1812
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1813
	}
1814

    
1815
	/*
1816
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1817
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1818
	 * Keep this in mind while doing changes here!
1819
	 */
1820
	if ($ifacecfg === false) {
1821
		$ifcfg = $iface;
1822
		$ppps = config_get_path('ppps/ppp', []);
1823
		$realif = get_real_interface($interface);
1824
		$realifv6 = get_real_interface($interface, "inet6", true);
1825
	} elseif (!is_array($ifacecfg)) {
1826
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1827
		$ifcfg = $iface;
1828
		$ppps = config_get_path('ppps/ppp', []);
1829
		$realif = get_real_interface($interface);
1830
		$realifv6 = get_real_interface($interface, "inet6", true);
1831
	} else {
1832
		$ifcfg = $ifacecfg['ifcfg'];
1833
		$ppps = $ifacecfg['ppps'];
1834
		if (isset($ifacecfg['ifcfg']['realif'])) {
1835
			$realif = $ifacecfg['ifcfg']['realif'];
1836
			/* XXX: Any better way? */
1837
			$realifv6 = $realif;
1838
		} else {
1839
			$realif = get_real_interface($interface);
1840
			$realifv6 = get_real_interface($interface, "inet6", true);
1841
		}
1842
	}
1843

    
1844
	/* check all gateways, including dynamic,
1845
	 * see https://redmine.pfsense.org/issues/12920 */
1846
	foreach (return_gateways_array(true) as $gw) {
1847
		if ($gw['friendlyiface'] == $interface) {
1848
			$restart_gateways_monitor = true;
1849
			break;
1850
		}
1851
	}
1852

    
1853
	switch ($ifcfg['ipaddr']) {
1854
		case "ppp":
1855
		case "pppoe":
1856
		case "pptp":
1857
		case "l2tp":
1858
			if (is_array($ppps) && count($ppps)) {
1859
				foreach ($ppps as  $ppp) {
1860
					if ($realif == $ppp['if']) {
1861
						if (isset($ppp['ondemand']) && !$destroy) {
1862
							send_event("interface reconfigure {$interface}");
1863
							break;
1864
						}
1865
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1866
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1867
							sleep(2);
1868
						}
1869
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1870
						break;
1871
					}
1872
				}
1873
			}
1874
			break;
1875
		case "dhcp":
1876
			kill_dhclient_process($realif);
1877
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1878
			if (does_interface_exist("$realif")) {
1879
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1880
				interface_vip_cleanup($interface, "inet4");
1881
				if ($destroy == true) {
1882
					pfSense_interface_flags($realif, -IFF_UP);
1883
				}
1884
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1885
			}
1886
			break;
1887
		default:
1888
			if (does_interface_exist("$realif")) {
1889
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1890
				interface_vip_cleanup($interface, "inet4");
1891
				if ($destroy == true) {
1892
					pfSense_interface_flags($realif, -IFF_UP);
1893
				}
1894
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1895
			}
1896
			break;
1897
	}
1898

    
1899
	$track6 = array();
1900
	switch ($ifcfg['ipaddrv6']) {
1901
		case "slaac":
1902
		case "dhcp6":
1903
			interface_dhcpv6_configure($interface, $ifcfg, true);
1904
			if (does_interface_exist($realifv6)) {
1905
				mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 -accept_rtadv");
1906
				$ip6 = find_interface_ipv6($realifv6);
1907
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1908
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1909
				}
1910
				interface_vip_cleanup($interface, "inet6");
1911
				if ($destroy == true) {
1912
					pfSense_interface_flags($realif, -IFF_UP);
1913
				}
1914
			}
1915
			$track6 = link_interface_to_track6($interface);
1916
			break;
1917
		case "6rd":
1918
		case "6to4":
1919
			$realif = "{$interface}_stf";
1920
			if (does_interface_exist("$realif")) {
1921
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1922
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($iface['ipaddrv6']) || $iface['ipaddrv6'] != '6rd')) ||
1923
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($iface['ipaddrv6']) || $iface['ipaddrv6'] != '6to4'))) {
1924
					$destroy = true;
1925
				} else {
1926
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1927
					$ip6 = get_interface_ipv6($interface);
1928
					if (is_ipaddrv6($ip6)) {
1929
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1930
					}
1931
				}
1932
				interface_vip_cleanup($interface, "inet6");
1933
				if ($destroy == true) {
1934
					pfSense_interface_flags($realif, -IFF_UP);
1935
				}
1936
			}
1937
			$track6 = link_interface_to_track6($interface);
1938
			break;
1939
		default:
1940
			if (does_interface_exist("$realif")) {
1941
				$ip6 = get_interface_ipv6($interface);
1942
				if (is_ipaddrv6($ip6)) {
1943
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1944
				}
1945
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1946
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1947
				}
1948
				interface_vip_cleanup($interface, "inet6");
1949
				if ($destroy == true) {
1950
					pfSense_interface_flags($realif, -IFF_UP);
1951
				}
1952
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1953
			}
1954
			$track6 = link_interface_to_track6($interface);
1955
			break;
1956
	}
1957

    
1958
	if (!empty($track6) && is_array($track6)) {
1959
		if (!function_exists('services_dhcpd_configure')) {
1960
			require_once('services.inc');
1961
		}
1962
		/* Bring down radvd and dhcp6 on these interfaces */
1963
		services_dhcpd_configure('inet6', $track6);
1964
	}
1965

    
1966
	/* remove interface up file if it exists */
1967
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1968
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1969
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
1970
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1971
		rename("{$g['tmp_path']}/{$realif}_router", "{$g['tmp_path']}/{$realif}_router.last");
1972
	}
1973
	if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
1974
		rename("{$g['tmp_path']}/{$realif}_routerv6", "{$g['tmp_path']}/{$realif}_routerv6.last");
1975
	}
1976
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
1977
	unlink_if_exists("{$g['varetc_path']}/nameserver_v6{$interface}");
1978
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
1979
	unlink_if_exists("{$g['varetc_path']}/searchdomain_v6{$interface}");
1980
	unlink_if_exists("{$g['tmp_path']}/{$interface}_upstart4");
1981
	unlink_if_exists("{$g['tmp_path']}/{$interface}_upstart6");
1982

    
1983
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
1984
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
1985
	if (is_array($ifcfg['wireless'])) {
1986
		kill_hostapd($realif);
1987
		mwexec(kill_wpasupplicant($realif));
1988
		unlink_if_exists("{$g['varetc_path']}/wpa_supplicant_{$realif}.*");
1989
		unlink_if_exists("{$g['varetc_path']}/hostapd_{$realif}.conf");
1990
	}
1991

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

    
1996
			/* Invalidate cache */
1997
			get_interface_arr(true);
1998
		}
1999
	}
2000

    
2001
	/* If interface has a gateway, we need to bounce dpinger to keep dpinger happy */
2002
	if ($restart_gateways_monitor) {
2003
		setup_gateways_monitor();
2004
	}
2005

    
2006
	return;
2007
}
2008

    
2009
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
2010
	if (config_path_enabled('/','virtualip_carp_maintenancemode') && ($carp_maintenancemode == false)) {
2011
		config_del_path('virtualip_carp_maintenancemode');
2012
		write_config("Leave CARP maintenance mode");
2013
	} elseif (!config_path_enabled('/','virtualip_carp_maintenancemode') && ($carp_maintenancemode == true)) {
2014
		config_set_path('virtualip_carp_maintenancemode', true);
2015
		write_config(gettext("Enter CARP maintenance mode"));
2016
	}
2017
	init_config_arr(array('virtualip', 'vip'));
2018

    
2019
	foreach (config_get_path('virtualip/vip', []) as $vip) {
2020
		if ($vip['mode'] == "carp") {
2021
			interface_carp_configure($vip, true);
2022
		}
2023
	}
2024
}
2025

    
2026
function interface_wait_tentative($interface, $timeout = 10) {
2027
	if (!does_interface_exist($interface)) {
2028
		return false;
2029
	}
2030

    
2031
	$time = 0;
2032
	while ($time <= $timeout) {
2033
		$if = get_interface_addresses($interface);
2034
		if (!isset($if['tentative'])) {
2035
			return true;
2036
		}
2037
		sleep(1);
2038
		$time++;
2039
	}
2040

    
2041
	return false;
2042
}
2043

    
2044
function interface_isppp_type($interface) {
2045
	$iface = config_get_path("interfaces/{$interface}");
2046
	if (!is_array($iface)) {
2047
		return false;
2048
	}
2049

    
2050
	switch ($iface['ipaddr']) {
2051
		case 'pptp':
2052
		case 'l2tp':
2053
		case 'pppoe':
2054
		case 'ppp':
2055
			return true;
2056
			break;
2057
		default:
2058
			return false;
2059
			break;
2060
	}
2061
}
2062

    
2063
function interfaces_ptpid_used($ptpid) {
2064
	$ppps = config_get_path('ppps/ppp');
2065
	if (is_array($ppps)) {
2066
		foreach ($ppps as $settings) {
2067
			if ($ptpid == $settings['ptpid']) {
2068
				return true;
2069
			}
2070
		}
2071
	}
2072

    
2073
	return false;
2074
}
2075

    
2076
function interfaces_ptpid_next() {
2077
	$ptpid = 0;
2078
	while (interfaces_ptpid_used($ptpid)) {
2079
		$ptpid++;
2080
	}
2081

    
2082
	return $ptpid;
2083
}
2084

    
2085
function getMPDCRONSettings($pppif) {
2086
	global $g;
2087

    
2088
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2089
	foreach (config_get_path('cron/item', []) as $i => $item) {
2090
		if (stripos($item['command'], $cron_cmd_file) !== false) {
2091
			return array("ID" => $i, "ITEM" => $item);
2092
		}
2093
	}
2094

    
2095
	return NULL;
2096
}
2097

    
2098
function handle_pppoe_reset($post_array) {
2099
	global $g;
2100

    
2101
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2102
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2103

    
2104
	if (!is_array(config_get_path('cron/item'))) {
2105
		if (config_set_path('cron/item', array()) === null)
2106
			log_error(gettext('Cron section in config root is invalid.'));
2107
			return;
2108
	}
2109

    
2110
	$itemhash = getMPDCRONSettings($pppif);
2111

    
2112
	// reset cron items if necessary and return
2113
	if (empty($post_array['pppoe-reset-type'])) {
2114
		if (isset($itemhash)) {
2115
			config_del_path("cron/item/{$itemhash['ID']}");
2116
		}
2117
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2118
		return;
2119
	}
2120

    
2121
	if (empty($itemhash)) {
2122
		$itemhash = array();
2123
	}
2124
	$item = array();
2125
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
2126
		$item['minute'] = $post_array['pppoe_resetminute'] ? $post_array['pppoe_resetminute'] : "*";
2127
		$item['hour'] = $post_array['pppoe_resethour'] ? $post_array['pppoe_resethour'] : "*";
2128
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
2129
			$date = explode("/", $post_array['pppoe_resetdate']);
2130
			$item['mday'] = $date[1];
2131
			$item['month'] = $date[0];
2132
		} else {
2133
			$item['mday'] = "*";
2134
			$item['month'] = "*";
2135
		}
2136
		$item['wday'] = "*";
2137
		$item['who'] = "root";
2138
		$item['command'] = $cron_cmd_file;
2139
	} elseif (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
2140
		switch ($post_array['pppoe_pr_preset_val']) {
2141
			case "monthly":
2142
				$item['minute'] = "0";
2143
				$item['hour'] = "0";
2144
				$item['mday'] = "1";
2145
				$item['month'] = "*";
2146
				$item['wday'] = "*";
2147
				break;
2148
			case "weekly":
2149
				$item['minute'] = "0";
2150
				$item['hour'] = "0";
2151
				$item['mday'] = "*";
2152
				$item['month'] = "*";
2153
				$item['wday'] = "0";
2154
				break;
2155
			case "daily":
2156
				$item['minute'] = "0";
2157
				$item['hour'] = "0";
2158
				$item['mday'] = "*";
2159
				$item['month'] = "*";
2160
				$item['wday'] = "*";
2161
				break;
2162
			case "hourly":
2163
				$item['minute'] = "0";
2164
				$item['hour'] = "*";
2165
				$item['mday'] = "*";
2166
				$item['month'] = "*";
2167
				$item['wday'] = "*";
2168
				break;
2169
		} // end switch
2170
		$item['who'] = "root";
2171
		$item['command'] = $cron_cmd_file;
2172
	}
2173
	if (empty($item)) {
2174
		return;
2175
	}
2176
	if (isset($itemhash['ID'])) {
2177
		config_set_path("cron/item/{$itemhash['ID']}", $item);
2178
	} else {
2179
		$items = config_get_path('cron/item', []);
2180
		$items[] = $item;
2181
		config_set_path('cron/item', $items);
2182
	}
2183
}
2184

    
2185
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2186
	$ppp_list = array();
2187
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
2188
		$ports = explode(",", $ppp['ports']);
2189
		foreach($ports as $port) {
2190
			foreach($triggerinterfaces as $vip) {
2191
				if ($port == "_vip{$vip['uniqid']}") {
2192
					$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2193
					$ppp_list[$if] = 1;
2194
				}
2195
			}
2196
		}
2197
	}
2198
	foreach(array_keys($ppp_list) as $pppif) {
2199
		interface_ppps_configure($pppif);
2200
	}
2201
}
2202

    
2203
/*
2204
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2205
 * It writes the mpd config file to /var/etc every time the link is opened.
2206
 */
2207
function interface_ppps_configure($interface) {
2208
	global $g;
2209

    
2210
	$iface = config_get_path("interfaces/{$interface}");
2211
	/* Return for unassigned interfaces. This is a minimum requirement. */
2212
	if (empty($iface)) {
2213
		return 0;
2214
	}
2215
	$ifcfg = $iface;
2216
	if (!isset($ifcfg['enable'])) {
2217
		return 0;
2218
	}
2219

    
2220
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2221
	if (!is_dir("/var/spool/lock")) {
2222
		mkdir("/var/spool/lock", 0777, true);
2223
	}
2224
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2225
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2226
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2227
	}
2228

    
2229
	$pppid = "";
2230
	$ppp = array();
2231
	$ppps = config_get_path('ppps/ppp');
2232
	if (is_array($ppps) && count($ppps)) {
2233
		foreach ($ppps as $pppid => $ppp) {
2234
			if ($ifcfg['if'] == $ppp['if']) {
2235
				break;
2236
			}
2237
		}
2238
	}
2239
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2240
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2241
		return 0;
2242
	}
2243
	$pppif = $ifcfg['if'];
2244
	if ($ppp['type'] == "ppp") {
2245
		$type = "modem";
2246
	} else {
2247
		$type = $ppp['type'];
2248
	}
2249

    
2250
	$confports = explode(',', $ppp['ports']);
2251
	if ($type == "modem") {
2252
		$ports = $confports;
2253
	} else {
2254
		$ports = array();
2255
		foreach ($confports as $pid => $port) {
2256
			if (strstr($port, "_vip")) {
2257
				if (get_carp_interface_status($port) != "MASTER") {
2258
					continue;
2259
				}
2260
			}
2261
			$ports[$pid] = get_real_interface($port);
2262
			if (empty($ports[$pid])) {
2263
				return 0;
2264
			}
2265
		}
2266
	}
2267
	$localips = explode(',', $ppp['localip']);
2268
	$gateways = explode(',', $ppp['gateway']);
2269
	$subnets = explode(',', $ppp['subnet']);
2270

    
2271
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2272
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2273
	 */
2274
	foreach ($ports as $pid => $port) {
2275
		switch ($ppp['type']) {
2276
			case "pppoe":
2277
				/* Bring the parent interface up */
2278
				interfaces_bring_up($port);
2279
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2280
				$ngif = str_replace(".", "_", $port);
2281
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2282
				break;
2283
			case "pptp":
2284
			case "l2tp":
2285
				/* configure interface */
2286
				if (is_ipaddr($localips[$pid])) {
2287
					// Manually configure interface IP/subnet
2288
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2289
					interfaces_bring_up($port);
2290
				} elseif (empty($localips[$pid])) {
2291
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2292
				}
2293

    
2294
				if (!is_ipaddr($localips[$pid])) {
2295
					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));
2296
					$localips[$pid] = "0.0.0.0";
2297
				}
2298
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2299
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2300
				}
2301
				if (!is_ipaddr($gateways[$pid])) {
2302
					log_error(sprintf(gettext('Could not get a PPTP/L2TP Remote IP address from %1$s for %2$s in interfaces_ppps_configure.'), $localips[$pid], $ppp['gateway']));
2303
					return 0;
2304
				}
2305
				break;
2306
			case "ppp":
2307
				if (!file_exists("{$port}")) {
2308
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2309
					return 0;
2310
				}
2311
				break;
2312
			default:
2313
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2314
				break;
2315
		}
2316
	}
2317

    
2318
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2319
	    (is_array($ports) && count($ports) > 1)) {
2320
		$multilink = "enable";
2321
	} else {
2322
		$multilink = "disable";
2323
	}
2324

    
2325
	if ($type == "modem") {
2326
		if (is_ipaddr($ppp['localip'])) {
2327
			$localip = $ppp['localip'];
2328
		} else {
2329
			$localip = '0.0.0.0';
2330
		}
2331

    
2332
		if (is_ipaddr($ppp['gateway'])) {
2333
			$gateway = $ppp['gateway'];
2334
		} else {
2335
			$gateway = "10.64.64.{$pppid}";
2336
		}
2337
		$ranges = "{$localip}/0 {$gateway}/0";
2338

    
2339
		if (empty($ppp['apnum'])) {
2340
			$ppp['apnum'] = 1;
2341
		}
2342
	} else {
2343
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2344
	}
2345

    
2346
	if (isset($ppp['ondemand'])) {
2347
		$ondemand = "enable";
2348
	} else {
2349
		$ondemand = "disable";
2350
	}
2351
	if (!isset($ppp['idletimeout'])) {
2352
		$ppp['idletimeout'] = 0;
2353
	}
2354

    
2355
	if (empty($ppp['username']) && $type == "modem") {
2356
		$ppp['username'] = "user";
2357
		$ppp['password'] = "none";
2358
	}
2359
	if (empty($ppp['password']) && $type == "modem") {
2360
		$passwd = "none";
2361
	} else {
2362
		$passwd = base64_decode($ppp['password']);
2363
	}
2364

    
2365
	$bandwidths = explode(',', $ppp['bandwidth']);
2366
	$defaultmtu = "1492";
2367
	if (!empty($ifcfg['mtu'])) {
2368
		$defaultmtu = intval($ifcfg['mtu']);
2369
	}
2370
	if (isset($ppp['mtu'])) {
2371
		$mtus = explode(',', $ppp['mtu']);
2372
	}
2373
	if (isset($ppp['mru'])) {
2374
		$mrus = explode(',', $ppp['mru']);
2375
	}
2376
	if (isset($ppp['mrru'])) {
2377
		$mrrus = explode(',', $ppp['mrru']);
2378
	}
2379
	if (!empty($ifcfg['ipaddrv6'])) {
2380
		$ipv6cp = "set bundle enable ipv6cp";
2381
	}
2382

    
2383
	// Construct the mpd.conf file
2384
	$mpdconf = <<<EOD
2385
startup:
2386
	# configure the console
2387
	set console close
2388
	# configure the web server
2389
	set web close
2390

    
2391
default:
2392
{$ppp['type']}client:
2393
	create bundle static {$interface}
2394
	set bundle period 6
2395
	set bundle lowat 0
2396
	set bundle hiwat 0
2397
	set bundle min-con 3
2398
	set bundle min-dis 6
2399
	set bundle enable bw-manage
2400
	{$ipv6cp}
2401
	set iface name {$pppif}
2402

    
2403
EOD;
2404

    
2405
	if (isset($ifcfg['descr'])) {
2406
		$mpdconf .= <<<EOD
2407
	set iface description "{$ifcfg['descr']}"
2408

    
2409
EOD;
2410
	}
2411
	$setdefaultgw = false;
2412
	$defgw4 = lookup_gateway_or_group_by_name(config_get_path('gateways/defaultgw4'));
2413
//	$defgw6 = lookup_gateway_or_group_by_name(config_get_path('gateways/defaultgw6'));
2414
	if ($defgw4['interface'] == $interface) {
2415
		$setdefaultgw = true;
2416
	}
2417

    
2418
/* Omit this, we maintain the default route by other means, and it causes problems with
2419
 * default gateway switching. See redmine #1837 for original issue
2420
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2421
 * edge case. redmine #6495 open to address.
2422
 */
2423
	if ($setdefaultgw == true) {
2424
		$mpdconf .= <<<EOD
2425
	set iface route default
2426

    
2427
EOD;
2428
	}
2429

    
2430
	$mpdconf .= <<<EOD
2431
	set iface {$ondemand} on-demand
2432
	set iface idle {$ppp['idletimeout']}
2433

    
2434
EOD;
2435

    
2436
	if (isset($ppp['ondemand'])) {
2437
		$mpdconf .= <<<EOD
2438
	set iface addrs 10.10.1.1 10.10.1.2
2439

    
2440
EOD;
2441
	}
2442

    
2443
	if (isset($ppp['mtu-override']) &&
2444
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2445
		/* Find the smaller MTU set on ports */
2446
		$mtu = $defaultmtu;
2447
		foreach ($ports as $pid => $port) {
2448
			if (empty($mtus[$pid])) {
2449
				$mtus[$pid] = $defaultmtu;
2450
			}
2451
			if ($type == "pppoe") {
2452
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2453
					$mtus[$pid] = get_interface_mtu($port) - 8;
2454
				}
2455
			}
2456
			if ($mtu > $mtus[$pid]) {
2457
				$mtu = $mtus[$pid];
2458
			}
2459
		}
2460
		$mpdconf .= <<<EOD
2461
	set iface mtu {$mtu} override
2462

    
2463
EOD;
2464
	}
2465

    
2466
	if (isset($ppp['tcpmssfix'])) {
2467
		$tcpmss = "disable";
2468
	} else {
2469
		$tcpmss = "enable";
2470
	}
2471
	$mpdconf .= <<<EOD
2472
	set iface {$tcpmss} tcpmssfix
2473

    
2474
EOD;
2475

    
2476
	$mpdconf .= <<<EOD
2477
	set iface up-script /usr/local/sbin/ppp-linkup
2478
	set iface down-script /usr/local/sbin/ppp-linkdown
2479
	set ipcp ranges {$ranges}
2480

    
2481
EOD;
2482
	if (isset($ppp['vjcomp'])) {
2483
		$mpdconf .= <<<EOD
2484
	set ipcp no vjcomp
2485

    
2486
EOD;
2487
	}
2488

    
2489
	if (config_get_path('system/dnsallowoverride')) {
2490
		$mpdconf .= <<<EOD
2491
	set ipcp enable req-pri-dns
2492
	set ipcp enable req-sec-dns
2493

    
2494
EOD;
2495
	}
2496

    
2497
	if (!isset($ppp['verbose_log'])) {
2498
		$mpdconf .= <<<EOD
2499
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2500

    
2501
EOD;
2502
	}
2503

    
2504
	foreach ($ports as $pid => $port) {
2505
		$port = get_real_interface($port);
2506
		$mpdconf .= <<<EOD
2507

    
2508
	create link static {$interface}_link{$pid} {$type}
2509
	set link action bundle {$interface}
2510
	set link {$multilink} multilink
2511
	set link keep-alive 10 60
2512
	set link max-redial 0
2513

    
2514
EOD;
2515
		if (isset($ppp['shortseq'])) {
2516
			$mpdconf .= <<<EOD
2517
	set link no shortseq
2518

    
2519
EOD;
2520
		}
2521

    
2522
		if (isset($ppp['acfcomp'])) {
2523
			$mpdconf .= <<<EOD
2524
	set link no acfcomp
2525

    
2526
EOD;
2527
		}
2528

    
2529
		if (isset($ppp['protocomp'])) {
2530
			$mpdconf .= <<<EOD
2531
	set link no protocomp
2532

    
2533
EOD;
2534
		}
2535

    
2536
		$mpdconf .= <<<EOD
2537
	set link disable chap pap
2538
	set link accept chap pap eap
2539
	set link disable incoming
2540

    
2541
EOD;
2542

    
2543

    
2544
		if (!empty($bandwidths[$pid])) {
2545
			$mpdconf .= <<<EOD
2546
	set link bandwidth {$bandwidths[$pid]}
2547

    
2548
EOD;
2549
		}
2550

    
2551
		if (empty($mtus[$pid])) {
2552
			$mtus[$pid] = $defaultmtu;
2553
		}
2554
		if ($type == "pppoe") {
2555
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2556
				$mtus[$pid] = get_interface_mtu($port) - 8;
2557
			}
2558
		}
2559
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2560
		    !isset($ppp['mtu-override']) &&
2561
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2562
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2563
			$mpdconf .= <<<EOD
2564
	set link mtu {$mtus[$pid]}
2565

    
2566
EOD;
2567
		}
2568

    
2569
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2570
		    !isset($ppp['mtu-override']) &&
2571
		    !empty($mrus[$pid])) {
2572
			$mpdconf .= <<<EOD
2573
	set link mru {$mrus[$pid]}
2574

    
2575
EOD;
2576
		}
2577

    
2578
		if (!empty($mrrus[$pid])) {
2579
			$mpdconf .= <<<EOD
2580
	set link mrru {$mrrus[$pid]}
2581

    
2582
EOD;
2583
		}
2584

    
2585
		$mpdconf .= <<<EOD
2586
	set auth authname "{$ppp['username']}"
2587
	set auth password {$passwd}
2588

    
2589
EOD;
2590
		if ($type == "modem") {
2591
			$mpdconf .= <<<EOD
2592
	set modem device {$ppp['ports']}
2593
	set modem script DialPeer
2594
	set modem idle-script Ringback
2595
	set modem watch -cd
2596
	set modem var \$DialPrefix "DT"
2597
	set modem var \$Telephone "{$ppp['phone']}"
2598

    
2599
EOD;
2600
		}
2601
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2602
			$mpdconf .= <<<EOD
2603
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2604

    
2605
EOD;
2606
		}
2607
		if (isset($ppp['initstr']) && $type == "modem") {
2608
			$initstr = base64_decode($ppp['initstr']);
2609
			$mpdconf .= <<<EOD
2610
	set modem var \$InitString "{$initstr}"
2611

    
2612
EOD;
2613
		}
2614
		if (isset($ppp['simpin']) && $type == "modem") {
2615
			if ($ppp['pin-wait'] == "") {
2616
				$ppp['pin-wait'] = 0;
2617
			}
2618
			$mpdconf .= <<<EOD
2619
	set modem var \$SimPin "{$ppp['simpin']}"
2620
	set modem var \$PinWait "{$ppp['pin-wait']}"
2621

    
2622
EOD;
2623
		}
2624
		if (isset($ppp['apn']) && $type == "modem") {
2625
			$mpdconf .= <<<EOD
2626
	set modem var \$APN "{$ppp['apn']}"
2627
	set modem var \$APNum "{$ppp['apnum']}"
2628

    
2629
EOD;
2630
		}
2631
		if ($type == "pppoe") {
2632
			$hostuniq = '';
2633
			if (!empty($ppp['hostuniq'])) {
2634
				if (preg_match('/^0x[a-fA-F0-9]+$/', $ppp['hostuniq'])) {
2635
					$hostuniq = strtolower($ppp['hostuniq']) .'|';
2636
				} elseif (preg_match('/^[a-zA-Z0-9]+$/i', $ppp['hostuniq'])) {
2637
					$hostuniq = '0x' . bin2hex($ppp['hostuniq']) . '|';
2638
				}
2639
			}
2640
			// Send a null service name if none is set.
2641
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2642
			$mpdconf .= <<<EOD
2643
	set pppoe service "{$hostuniq}{$provider}"
2644

    
2645
EOD;
2646
		}
2647
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2648
			$mpdconf .= <<<EOD
2649
	set pppoe max-payload {$mtus[$pid]}
2650

    
2651
EOD;
2652
		}
2653
		if ($type == "pppoe") {
2654
			$mpdconf .= <<<EOD
2655
	set pppoe iface {$port}
2656

    
2657
EOD;
2658
		}
2659

    
2660
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2661
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2662
			$mpdconf .= <<<EOD
2663
	set l2tp secret "{$secret}"
2664

    
2665
EOD;
2666
		}
2667

    
2668
		if (($type == "pptp") || ($type == "l2tp")) {
2669
			$mpdconf .= <<<EOD
2670
	set {$type} self {$localips[$pid]}
2671
	set {$type} peer {$gateways[$pid]}
2672

    
2673
EOD;
2674
		}
2675

    
2676
		$mpdconf .= "\topen\n";
2677
	} //end foreach ($port)
2678

    
2679

    
2680
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2681
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2682
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2683
	} else {
2684
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2685
		if (!$fd) {
2686
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2687
			return 0;
2688
		}
2689
		// Write out mpd_ppp.conf
2690
		fwrite($fd, $mpdconf);
2691
		fclose($fd);
2692
		unset($mpdconf);
2693
	}
2694

    
2695
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2696
	if (isset($ppp['uptime'])) {
2697
		if (!file_exists("/conf/{$pppif}.log")) {
2698
			file_put_contents("/conf/{$pppif}.log", '');
2699
		}
2700
	} else {
2701
		if (file_exists("/conf/{$pppif}.log")) {
2702
			@unlink("/conf/{$pppif}.log");
2703
		}
2704
	}
2705

    
2706
	/* clean up old lock files */
2707
	foreach ($ports as $port) {
2708
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2709
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2710
		}
2711
	}
2712

    
2713
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2714
	/* random IPv6 interface identifier during boot. More details at */
2715
	/* https://forum.netgate.com/post/592474 */
2716
	if (platform_booting()) {
2717
		$count = 0;
2718
		foreach (config_get_path('interfaces', []) as $tempifacename => $tempiface) {
2719
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2720
				$tempaddr[$count]['if'] = $tempiface['if'];
2721
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2722
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2723
				$count++;
2724
			}
2725
			// Maximum /31 is is x.y.z.254/31
2726
			if ($count > 122) {
2727
				break;
2728
			}
2729
		}
2730
		unset($count);
2731
	}
2732

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

    
2738
	// Check for PPPoE periodic reset request
2739
	if ($type == "pppoe") {
2740
		if (!empty($ppp['pppoe-reset-type'])) {
2741
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2742
		} else {
2743
			interface_setup_pppoe_reset_file($ppp['if']);
2744
		}
2745
	}
2746
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2747
	$i = 0;
2748
	while ($i < 10) {
2749
		if (does_interface_exist($ppp['if'], true)) {
2750
			break;
2751
		}
2752
		sleep(3);
2753
		$i++;
2754
	}
2755

    
2756
	/* Remove all temporary bogon IPv4 addresses */
2757
	if (is_array($tempaddr)) {
2758
		foreach ($tempaddr as $tempiface) {
2759
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2760
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2761
			}
2762
		}
2763
		unset ($tempaddr);
2764
	}
2765

    
2766
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2767
	/* We should be able to launch the right version for each modem */
2768
	/* We can also guess the mondev from the manufacturer */
2769
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2770
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2771
	foreach ($ports as $port) {
2772
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2773
			$mondev = substr(basename($port), 0, -1);
2774
			$devlist = glob("/dev/{$mondev}?");
2775
			$mondev = basename(end($devlist));
2776
		}
2777
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2778
			$mondev = substr(basename($port), 0, -1) . "1";
2779
		}
2780
		if ($mondev != '') {
2781
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2782
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2783
		}
2784
	}
2785

    
2786
	return 1;
2787
}
2788

    
2789
function interfaces_sync_setup() {
2790

    
2791
	if (config_get_path('system/developerspew')) {
2792
		$mt = microtime();
2793
		echo "interfaces_sync_setup() being called $mt\n";
2794
	}
2795

    
2796
	if (platform_booting()) {
2797
		echo gettext("Configuring CARP settings...");
2798
		mute_kernel_msgs();
2799
	}
2800

    
2801
	/* suck in configuration items */
2802
	if (!empty(config_get_path('hasync'))) {
2803
		$pfsyncenabled = config_get_path('hasync/pfsyncenabled');
2804
		$pfsyncinterface = config_get_path('hasync/pfsyncinterface');
2805
		$pfsyncpeerip = config_get_path('hasync/pfsyncpeerip');
2806
	}
2807

    
2808
	set_sysctl(array(
2809
		"net.inet.carp.preempt" => "1",
2810
		"net.inet.carp.log" => "1")
2811
	);
2812

    
2813
	if (!empty($pfsyncinterface)) {
2814
		$carp_sync_int = get_real_interface($pfsyncinterface);
2815
	}
2816

    
2817
	/* setup pfsync interface */
2818
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2819
		if (is_ipaddr($pfsyncpeerip)) {
2820
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2821
		} else {
2822
			$syncpeer = "-syncpeer";
2823
		}
2824

    
2825
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} " .
2826
		    "{$syncpeer} up");
2827
		mwexec("/sbin/ifconfig pfsync0 -defer");
2828

    
2829
		/*
2830
		 * XXX: Handle an issue with pfsync(4) and carp(4). In a
2831
		 * cluster carp will come up before pfsync(4) has updated and
2832
		 * so will cause issues for existing sessions.
2833
		 */
2834
		log_error(gettext("waiting for pfsync..."));
2835

    
2836
		$i = 0;
2837
		do {
2838
			sleep(1);
2839
			exec('/sbin/ifconfig pfsync0 | ' .
2840
				 '/usr/bin/grep -q "syncok: 0" 2>/dev/null', $output,
2841
				 $rc);
2842
			$i++;
2843
		} while ($rc != 0 && $i <= 30);
2844

    
2845
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2846
		log_error(gettext("Configuring CARP settings finalize..."));
2847
	} else {
2848
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down");
2849
	}
2850

    
2851
	$carplist = get_configured_vip_list('all', VIP_CARP);
2852
	if (is_array($carplist) && count($carplist) > 0) {
2853
		set_single_sysctl("net.inet.carp.allow", "1");
2854
	} else {
2855
		set_single_sysctl("net.inet.carp.allow", "0");
2856
	}
2857

    
2858
	if (platform_booting()) {
2859
		unmute_kernel_msgs();
2860
		echo gettext("done.") . "\n";
2861
	}
2862
}
2863

    
2864
function interface_proxyarp_configure($interface = "") {
2865
	global $g;
2866
	if (config_get_path('system/developerspew')) {
2867
		$mt = microtime();
2868
		echo "interface_proxyarp_configure() being called $mt\n";
2869
	}
2870

    
2871
	/* kill any running choparp */
2872
	if (empty($interface)) {
2873
		killbyname("choparp");
2874
	} else {
2875
		$vipif = get_real_interface($interface);
2876
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2877
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2878
		}
2879
	}
2880

    
2881
	$paa = array();
2882
	$vips = config_get_path('virtualip/vip');
2883
	if (is_array($vips)) {
2884

    
2885
		/* group by interface */
2886
		foreach ($vips as $vipent) {
2887
			if ($vipent['mode'] === "proxyarp") {
2888
				if ($vipent['interface']) {
2889
					$proxyif = $vipent['interface'];
2890
				} else {
2891
					$proxyif = "wan";
2892
				}
2893

    
2894
				if (!empty($interface) && $interface != $proxyif) {
2895
					continue;
2896
				}
2897

    
2898
				if (!is_array($paa[$proxyif])) {
2899
					$paa[$proxyif] = array();
2900
				}
2901

    
2902
				$paa[$proxyif][] = $vipent;
2903
			}
2904
		}
2905
	}
2906

    
2907
	if (!empty($interface)) {
2908
		if (is_array($paa[$interface])) {
2909
			$paaifip = get_interface_ip($interface);
2910
			if (!is_ipaddr($paaifip)) {
2911
				return;
2912
			}
2913
			$vipif = get_real_interface($interface);
2914
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2915
			$args .= $vipif . " auto";
2916
			foreach ($paa[$interface] as $paent) {
2917
				if (isset($paent['subnet'])) {
2918
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2919
				} elseif (isset($paent['range'])) {
2920
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2921
				}
2922
			}
2923
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2924
		}
2925
	} elseif (count($paa) > 0) {
2926
		foreach ($paa as $paif => $paents) {
2927
			$paaifip = get_interface_ip($paif);
2928
			if (!is_ipaddr($paaifip)) {
2929
				continue;
2930
			}
2931
			$vipif = get_real_interface($paif);
2932
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2933
			$args .= $vipif . " auto";
2934
			foreach ($paents as $paent) {
2935
				if (isset($paent['subnet'])) {
2936
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2937
				} elseif (isset($paent['range'])) {
2938
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2939
				}
2940
			}
2941
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2942
		}
2943
	}
2944
}
2945

    
2946
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2947
	$vips = config_get_path('virtualip/vip');
2948
	if (is_array($vips)) {
2949
		foreach ($vips as $vip) {
2950

    
2951
			$iface = $vip['interface'];
2952
			if (substr($iface, 0, 4) == "_vip")
2953
				$iface = get_configured_vip_interface($vip['interface']);
2954
			if ($iface != $interface)
2955
				continue;
2956
			if ($type == VIP_CARP) {
2957
				if ($vip['mode'] != "carp")
2958
					continue;
2959
			} elseif ($type == VIP_IPALIAS) {
2960
				if ($vip['mode'] != "ipalias")
2961
					continue;
2962
			} else {
2963
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2964
					continue;
2965
			}
2966

    
2967
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2968
				interface_vip_bring_down($vip);
2969
			elseif ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2970
				interface_vip_bring_down($vip);
2971
			elseif ($inet == "all")
2972
				interface_vip_bring_down($vip);
2973
		}
2974
	}
2975
}
2976

    
2977
function interfaces_vips_configure($interface = "") {
2978
	if (config_get_path('system/developerspew')) {
2979
		$mt = microtime();
2980
		echo "interfaces_vips_configure() being called $mt\n";
2981
	}
2982

    
2983
	$vips = config_get_path('virtualip/vip');
2984
	if (!is_array($vips)) {
2985
		return;
2986
	}
2987

    
2988
	$carp_setuped = false;
2989
	$anyproxyarp = false;
2990
	foreach ($vips as $vip) {
2991
		if ($interface <> "" &&
2992
		    get_root_interface($vip['interface']) <> $interface) {
2993
			continue;
2994
		}
2995
		switch ($vip['mode']) {
2996
			case "proxyarp":
2997
				/*
2998
				 * nothing it is handled on
2999
				 * interface_proxyarp_configure()
3000
				 */
3001
				$anyproxyarp = true;
3002
				break;
3003
			case "ipalias":
3004
				interface_ipalias_configure($vip);
3005
				break;
3006
			case "carp":
3007
				if ($carp_setuped == false) {
3008
					$carp_setuped = true;
3009
				}
3010
				interface_carp_configure($vip);
3011
				break;
3012
		}
3013
	}
3014
	if ($carp_setuped == true) {
3015
		interfaces_sync_setup();
3016
	}
3017
	if ($anyproxyarp == true) {
3018
		interface_proxyarp_configure();
3019
	}
3020
}
3021

    
3022
function interface_ipalias_configure(&$vip) {
3023
	$gateway = '';
3024
	if ($vip['mode'] != 'ipalias') {
3025
		return;
3026
	}
3027

    
3028
	$realif = get_real_interface("_vip{$vip['uniqid']}");
3029
	if ($realif != "lo0") {
3030
		$if = convert_real_interface_to_friendly_interface_name($realif);
3031
		if (!config_path_enabled("interfaces/{$if}")) {
3032
			return;
3033
		}
3034
		if (is_pseudo_interface($realif)) {
3035
			if (is_ipaddrv4($vip['subnet'])) {
3036
				$gateway = get_interface_gateway($if);
3037
			} else {
3038
				$gateway = get_interface_gateway_v6($if);
3039
			}
3040
		}
3041
	}
3042

    
3043
	$af = 'inet';
3044
	if (is_ipaddrv6($vip['subnet'])) {
3045
		$af = 'inet6';
3046
	}
3047
	$iface = $vip['interface'];
3048
	$vhid = '';
3049
	if (substr($vip['interface'], 0, 4) == "_vip") {
3050
		$carpvip = get_configured_vip($vip['interface']);
3051
		$iface = $carpvip['interface'];
3052
		$vhid = "vhid {$carpvip['vhid']}";
3053
	}
3054
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$gateway} {$vhid}");
3055
	unset($iface, $af, $realif, $carpvip, $vhid, $gateway);
3056
}
3057

    
3058
function interface_carp_configure(&$vip, $maintenancemode_only = false, $ipalias_reload = false) {
3059
	if (config_get_path('system/developerspew')) {
3060
		$mt = microtime();
3061
		echo "interface_carp_configure() being called $mt\n";
3062
	}
3063

    
3064
	if ($vip['mode'] != "carp") {
3065
		return;
3066
	}
3067

    
3068
	$realif = get_real_interface($vip['interface']);
3069
	if (!does_interface_exist($realif)) {
3070
		file_notice("CARP", sprintf(gettext(
3071
		    "Interface specified for the virtual IP address %s does not exist. Skipping this VIP."),
3072
		    $vip['subnet']), "Firewall: Virtual IP", "");
3073
		return;
3074
	}
3075
	if ($realif != "lo0") {
3076
		if (!config_path_enabled("interfaces/{$vip['interface']}")) {
3077
			return;
3078
		}
3079
	}
3080

    
3081
	$vip_password = $vip['password'];
3082
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3083
	    $vip_password)));
3084
	if ($vip['password'] != "") {
3085
		$password = " pass {$vip_password}";
3086
	}
3087

    
3088
	$advbase = "";
3089
	if (!empty($vip['advbase'])) {
3090
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3091
	}
3092

    
3093
	$carp_maintenancemode = config_path_enabled('/','virtualip_carp_maintenancemode');
3094
	if ($carp_maintenancemode) {
3095
		$advskew = "advskew 254";
3096
	} else {
3097
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3098
	}
3099

    
3100
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) .
3101
	    " {$advskew} {$advbase} {$password}");
3102

    
3103
	if (!$maintenancemode_only) {
3104
		if (is_ipaddrv4($vip['subnet'])) {
3105
			mwexec("/sbin/ifconfig {$realif} " .
3106
			    escapeshellarg($vip['subnet']) . "/" .
3107
			    escapeshellarg($vip['subnet_bits']) .
3108
			    " alias vhid " . escapeshellarg($vip['vhid']));
3109
		} elseif (is_ipaddrv6($vip['subnet'])) {
3110
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3111
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3112
			    escapeshellarg($vip['subnet_bits']) .
3113
			    " alias vhid " . escapeshellarg($vip['vhid']));
3114
		}
3115
	}
3116

    
3117
	/* reconfigure stacked IP Aliases after CARP VIP changes
3118
	 * see https://redmine.pfsense.org/issues/12227
3119
	 * and https://redmine.pfsense.org/issues/12961 */
3120
	if ($ipalias_reload) {
3121
		foreach (config_get_path('virtualip/vip', []) as $viface) {
3122
			if (($viface['mode'] == 'ipalias') &&
3123
			    (get_root_interface($viface['interface']) == $vip['interface'])) { 
3124
				interface_vip_bring_down($viface);
3125
				interface_ipalias_configure($viface);
3126
			}
3127
		}
3128
	}
3129

    
3130
	return $realif;
3131
}
3132

    
3133
function interface_wireless_clone($realif, $wlcfg) {
3134
	global $g;
3135
	/*   Check to see if interface has been cloned as of yet.
3136
	 *   If it has not been cloned then go ahead and clone it.
3137
	 */
3138
	$needs_clone = false;
3139
	if (is_array($wlcfg['wireless'])) {
3140
		$wlcfg_mode = $wlcfg['wireless']['mode'];
3141
	} else {
3142
		$wlcfg_mode = $wlcfg['mode'];
3143
	}
3144
	switch ($wlcfg_mode) {
3145
		case "hostap":
3146
			$mode = "wlanmode hostap";
3147
			break;
3148
		case "adhoc":
3149
			$mode = "wlanmode adhoc";
3150
			break;
3151
		default:
3152
			$mode = "";
3153
			break;
3154
	}
3155
	$baseif = interface_get_wireless_base($wlcfg['if']);
3156
	if (does_interface_exist($realif)) {
3157
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
3158
		$ifconfig_str = implode($output);
3159
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
3160
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
3161
			$needs_clone = true;
3162
		}
3163
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
3164
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
3165
			$needs_clone = true;
3166
		}
3167
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
3168
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
3169
			$needs_clone = true;
3170
		}
3171
	} else {
3172
		$needs_clone = true;
3173
	}
3174

    
3175
	if ($needs_clone == true) {
3176
		/* remove previous instance if it exists */
3177
		if (does_interface_exist($realif)) {
3178
			pfSense_interface_destroy($realif);
3179

    
3180
			/* Invalidate cache */
3181
			get_interface_arr(true);
3182
		}
3183

    
3184
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
3185
		// Create the new wlan interface. FreeBSD returns the new interface name.
3186
		// example:  wlan2
3187
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
3188
		if ($ret <> 0) {
3189
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
3190
			return false;
3191
		}
3192
		$newif = trim($out[0]);
3193
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
3194
		pfSense_interface_rename($newif, $realif);
3195
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
3196
	}
3197
	return true;
3198
}
3199

    
3200
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3201

    
3202
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3203
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3204
				 'regdomain', 'regcountry', 'reglocation');
3205

    
3206
	if (!is_interface_wireless($ifcfg['if'])) {
3207
		return;
3208
	}
3209

    
3210
	$baseif = interface_get_wireless_base($ifcfg['if']);
3211

    
3212
	// Sync shared settings for assigned clones
3213
	$iflist = get_configured_interface_list(true);
3214
	foreach ($iflist as $if) {
3215
		if (($baseif == interface_get_wireless_base(config_get_path("interfaces/{$if}/if"))) &&
3216
			($ifcfg['if'] != config_get_path("interfaces/{$if}/if"))) {
3217
			if (config_path_enabled("interfaces/{$if}/wireless", 'standard') || $sync_changes) {
3218
				foreach ($shared_settings as $setting) {
3219
					if ($sync_changes) {
3220
						if (isset($ifcfg['wireless'][$setting])) {
3221
							config_set_path("interfaces/{$if}/wireless/{$setting}",
3222
											$ifcfg['wireless'][$setting]);
3223
						} elseif (!empty(config_get_path("interfaces/{$if}/wireless/{$setting}"))) {
3224
							config_del_path("interfaces/{$if}/wireless/{$setting}");
3225
						}
3226
					} else {
3227
						if (!empty(config_get_path("interfaces/{$if}/wireless/{$setting}"))) {
3228
							$ifcfg['wireless'][$setting] =
3229
							    config_get_path("interfaces/{$if}/wireless/{$setting}");
3230
						} elseif (isset($ifcfg['wireless'][$setting])) {
3231
							unset($ifcfg['wireless'][$setting]);
3232
						}
3233
					}
3234
				}
3235
				if (!$sync_changes) {
3236
					break;
3237
				}
3238
			}
3239
		}
3240
	}
3241

    
3242
	// Read or write settings at shared area
3243
	if (!empty(config_get_path("wireless/interfaces/{$baseif}"))) {
3244
		foreach ($shared_settings as $setting) {
3245
			if ($sync_changes) {
3246
				if (isset($ifcfg['wireless'][$setting])) {
3247
					config_set_path("wireless/interfaces/{$baseif}/{$setting}",
3248
									$ifcfg['wireless'][$setting]);
3249
				} elseif (!empty(config_get_path("wireless/interfaces/{$baseif}/{$setting}"))) {
3250
					config_del_path("wireless/interfaces/{$baseif}/{$setting}");
3251
				}
3252
			} else {
3253
				if (!empty(config_get_path("wireless/interfaces/{$baseif}/{$setting}"))) {
3254
					$ifcfg['wireless'][$setting] = config_get_path("wireless/interfaces/{$baseif}/{$setting}");
3255
				} elseif (isset($ifcfg['wireless'][$setting])) {
3256
					unset($ifcfg['wireless'][$setting]);
3257
				}
3258
			}
3259
		}
3260
	}
3261

    
3262
	// Sync the mode on the clone creation page with the configured mode on the interface
3263
	if (interface_is_wireless_clone($ifcfg['if'])) {
3264
		foreach (config_get_path('wireless/clone', []) as $key => $clone) {
3265
			if ($clone['cloneif'] == $ifcfg['if']) {
3266
				if ($sync_changes) {
3267
					config_set_path("wireless/clone/{$key}/mode)", $ifcfg['wireless']['mode']);
3268
				} else {
3269
					$ifcfg['wireless']['mode'] = $clone['mode'];
3270
				}
3271
				break;
3272
			}
3273
		}
3274
		unset($clone);
3275
	}
3276
}
3277

    
3278
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3279
	global $g;
3280

    
3281
	/*    open up a shell script that will be used to output the commands.
3282
	 *    since wireless is changing a lot, these series of commands are fragile
3283
	 *    and will sometimes need to be verified by a operator by executing the command
3284
	 *    and returning the output of the command to the developers for inspection.  please
3285
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3286
	 */
3287

    
3288
	// Remove script file
3289
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3290

    
3291
	// Clone wireless nic if needed.
3292
	interface_wireless_clone($if, $wl);
3293

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

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

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

    
3303
	/* set values for /path/program */
3304
	if (file_exists("/usr/local/sbin/hostapd")) {
3305
		$hostapd = "/usr/local/sbin/hostapd";
3306
	} else {
3307
		$hostapd = "/usr/sbin/hostapd";
3308
	}
3309
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3310
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3311
	} else {
3312
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3313
	}
3314
	$ifconfig = "/sbin/ifconfig";
3315
	$sysctl = "/sbin/sysctl";
3316
	$sysctl_args = "-q";
3317

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

    
3320
	$wlcmd = array();
3321
	$wl_sysctl = array();
3322
	/* Set a/b/g standard */
3323
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3324
	/* skip mode entirely for "auto" */
3325
	if ($wlcfg['standard'] != "auto") {
3326
		$wlcmd[] = "mode " . escapeshellarg($standard);
3327
	}
3328

    
3329
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3330
	 * to prevent massive packet loss under certain conditions. */
3331
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3332
		$wlcmd[] = "-ampdu";
3333
	}
3334

    
3335
	/* Set ssid */
3336
	if ($wlcfg['ssid']) {
3337
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3338
	}
3339

    
3340
	/* Set 802.11g protection mode */
3341
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3342

    
3343
	/* set wireless channel value */
3344
	if (isset($wlcfg['channel'])) {
3345
		if ($wlcfg['channel'] == "0") {
3346
			$wlcmd[] = "channel any";
3347
		} else {
3348
			if ($wlcfg['channel_width'] != "0") {
3349
				$channel_width = ":" . $wlcfg['channel_width'];
3350
			} else {
3351
				$channel_width = '';
3352
			}
3353
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3354
		}
3355
	}
3356

    
3357
	/* Set antenna diversity value */
3358
	if (isset($wlcfg['diversity'])) {
3359
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3360
	}
3361

    
3362
	/* Set txantenna value */
3363
	if (isset($wlcfg['txantenna'])) {
3364
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3365
	}
3366

    
3367
	/* Set rxantenna value */
3368
	if (isset($wlcfg['rxantenna'])) {
3369
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3370
	}
3371

    
3372
	/* set Distance value */
3373
	if ($wlcfg['distance']) {
3374
		$distance = escapeshellarg($wlcfg['distance']);
3375
	}
3376

    
3377
	/* Set wireless hostap mode */
3378
	if ($wlcfg['mode'] == "hostap") {
3379
		$wlcmd[] = "mediaopt hostap";
3380
	} else {
3381
		$wlcmd[] = "-mediaopt hostap";
3382
	}
3383

    
3384
	/* Set wireless adhoc mode */
3385
	if ($wlcfg['mode'] == "adhoc") {
3386
		$wlcmd[] = "mediaopt adhoc";
3387
	} else {
3388
		$wlcmd[] = "-mediaopt adhoc";
3389
	}
3390

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

    
3393
	/* handle hide ssid option */
3394
	if (isset($wlcfg['hidessid']['enable'])) {
3395
		$wlcmd[] = "hidessid";
3396
	} else {
3397
		$wlcmd[] = "-hidessid";
3398
	}
3399

    
3400
	/* handle pureg (802.11g) only option */
3401
	if (isset($wlcfg['pureg']['enable'])) {
3402
		$wlcmd[] = "mode 11g pureg";
3403
	} else {
3404
		$wlcmd[] = "-pureg";
3405
	}
3406

    
3407
	/* handle puren (802.11n) only option */
3408
	if (isset($wlcfg['puren']['enable'])) {
3409
		$wlcmd[] = "puren";
3410
	} else {
3411
		$wlcmd[] = "-puren";
3412
	}
3413

    
3414
	/* enable apbridge option */
3415
	if (isset($wlcfg['apbridge']['enable'])) {
3416
		$wlcmd[] = "apbridge";
3417
	} else {
3418
		$wlcmd[] = "-apbridge";
3419
	}
3420

    
3421
	/* handle turbo option */
3422
	if (isset($wlcfg['turbo']['enable'])) {
3423
		$wlcmd[] = "mediaopt turbo";
3424
	} else {
3425
		$wlcmd[] = "-mediaopt turbo";
3426
	}
3427

    
3428
	/* handle txpower setting */
3429
	// or don't. this has issues at the moment.
3430
	/*
3431
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3432
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3433
	}*/
3434

    
3435
	/* handle wme option */
3436
	if (isset($wlcfg['wme']['enable'])) {
3437
		$wlcmd[] = "wme";
3438
	} else {
3439
		$wlcmd[] = "-wme";
3440
	}
3441

    
3442
	/* Enable wpa if it's configured. No WEP support anymore. */
3443
	if (isset($wlcfg['wpa']['enable'])) {
3444
		$wlcmd[] = "authmode wpa wepmode off ";
3445
	} else {
3446
		$wlcmd[] = "authmode open wepmode off ";
3447
	}
3448

    
3449
	kill_hostapd($if);
3450
	mwexec(kill_wpasupplicant("{$if}"));
3451

    
3452
	$wpa_supplicant_file = "{$g['varetc_path']}/wpa_supplicant_{$if}.";
3453
	$hostapd_conf = "{$g['varetc_path']}/hostapd_{$if}.conf";
3454

    
3455
	unlink_if_exists("{$wpa_supplicant_file}*");
3456
	unlink_if_exists($hostapd_conf);
3457

    
3458
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3459
	$wpa = "";
3460
	switch ($wlcfg['mode']) {
3461
		case 'bss':
3462
			if (isset($wlcfg['wpa']['enable'])) {
3463
				$wpa .= <<<EOD
3464
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3465
ctrl_interface_group=0
3466
ap_scan=1
3467
#fast_reauth=1
3468
network={
3469
ssid="{$wlcfg['ssid']}"
3470
scan_ssid=1
3471
priority=5
3472
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3473
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3474
group={$wlcfg['wpa']['wpa_pairwise']}
3475

    
3476
EOD;
3477
				if ($wlcfg['wpa']['wpa_key_mgmt'] == 'WPA-EAP') {
3478
					if (($wlcfg['wpa']['wpa_eap_client_mode'] == 'PEAP') ||
3479
					    ($wlcfg['wpa']['wpa_eap_client_mode'] == 'TTLS')) {
3480
						if ($wlcfg['wpa']['wpa_eap_inner_auth'] == 'MSCHAPV2') {
3481
							$wpa .= "phase1=\"peaplabel=0\"\n";
3482
						}
3483
						$wpa .= "phase2=\"auth={$wlcfg['wpa']['wpa_eap_inner_auth']}\"\n";
3484
						$wpa .= "identity=\"{$wlcfg['wpa']['wpa_eap_inner_id']}\"\n";
3485
						$eappass = base64_decode($wlcfg['wpa']['wpa_eap_inner_password']);
3486
						$wpa .= "password=\"{$eappass}\"\n";
3487
					}
3488
					if (strstr($wlcfg['wpa']['wpa_eap_client_mode'], 'TLS')) { 
3489
						$cert = lookup_cert($wlcfg['wpa']['wpa_eap_cert']);
3490
						$wpa_supplicant_crt = $wpa_supplicant_file . "crt";
3491
						$wpa_supplicant_key = $wpa_supplicant_file . "key";
3492
						@file_put_contents($wpa_supplicant_crt, base64_decode($cert['crt']) . "\n" .
3493
						    ca_chain($cert)); 
3494
						@file_put_contents($wpa_supplicant_key, base64_decode($cert['prv'])); 
3495
						@chmod($wpa_supplicant_crt, 0600);
3496
						@chmod($wpa_supplicant_key, 0600);
3497
						$wpa .= "client_cert=\"{$wpa_supplicant_crt}\"\n";
3498
						$wpa .= "private_key=\"{$wpa_supplicant_key}\"\n";
3499
					}
3500
					$ca = lookup_ca($wlcfg['wpa']['wpa_eap_ca']);
3501
					$wpa_supplicant_ca = $wpa_supplicant_file . "ca";
3502
					@file_put_contents($wpa_supplicant_ca, base64_decode($ca['crt']) . "\n" .
3503
					    ca_chain($ca)); 
3504
					$wpa .= "ca_cert=\"{$wpa_supplicant_ca}\"\n";
3505
					$wpa .= "eap={$wlcfg['wpa']['wpa_eap_client_mode']}\n";
3506
				} else {
3507
					$wpa .= "psk=\"{$wlcfg['wpa']['passphrase']}\"\n";
3508
				}
3509
				$wpa .= "}\n";
3510

    
3511
				@file_put_contents($wpa_supplicant_file . "conf", $wpa);
3512
				unset($wpa);
3513
			}
3514
			break;
3515
		case 'hostap':
3516
			if (!empty($wlcfg['wpa']['passphrase'])) {
3517
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3518
			} else {
3519
				$wpa_passphrase = "";
3520
			}
3521
			if (isset($wlcfg['wpa']['enable'])) {
3522
				$wpa .= <<<EOD
3523
interface={$if}
3524
driver=bsd
3525
logger_syslog=-1
3526
logger_syslog_level=0
3527
logger_stdout=-1
3528
logger_stdout_level=0
3529
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3530
ctrl_interface={$g['varrun_path']}/hostapd
3531
ctrl_interface_group=wheel
3532
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3533
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3534
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3535
ssid={$wlcfg['ssid']}
3536
debug={$wlcfg['wpa']['debug_mode']}
3537
wpa={$wlcfg['wpa']['wpa_mode']}
3538
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3539
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3540
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3541
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3542
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3543
{$wpa_passphrase}
3544

    
3545
EOD;
3546

    
3547
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3548
					$wpa .= <<<EOD
3549
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3550
rsn_preauth=1
3551
rsn_preauth_interfaces={$if}
3552

    
3553
EOD;
3554
				}
3555
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3556
					$wpa .= "ieee8021x=1\n";
3557

    
3558
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3559
						$auth_server_port = "1812";
3560
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3561
							$auth_server_port = intval($wlcfg['auth_server_port']);
3562
						}
3563
						$wpa .= <<<EOD
3564

    
3565
auth_server_addr={$wlcfg['auth_server_addr']}
3566
auth_server_port={$auth_server_port}
3567
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3568

    
3569
EOD;
3570
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3571
							$auth_server_port2 = "1812";
3572
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3573
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3574
							}
3575

    
3576
							$wpa .= <<<EOD
3577
auth_server_addr={$wlcfg['auth_server_addr2']}
3578
auth_server_port={$auth_server_port2}
3579
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3580

    
3581
EOD;
3582
						}
3583
					}
3584
				}
3585

    
3586
				@file_put_contents($hostapd_conf, $wpa);
3587
				unset($wpa);
3588
			}
3589
			break;
3590
	}
3591

    
3592
	/*
3593
	 *    all variables are set, lets start up everything
3594
	 */
3595

    
3596
	$baseif = interface_get_wireless_base($if);
3597
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3598
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3599

    
3600
	/* set sysctls for the wireless interface */
3601
	if (!empty($wl_sysctl)) {
3602
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3603
		foreach ($wl_sysctl as $wl_sysctl_line) {
3604
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3605
		}
3606
	}
3607

    
3608
	/* set ack timers according to users preference (if he/she has any) */
3609
	if ($distance) {
3610
		fwrite($fd_set, "# Enable ATH distance settings\n");
3611
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3612
	}
3613

    
3614
	if (isset($wlcfg['wpa']['enable'])) {
3615
		if ($wlcfg['mode'] == "bss") {
3616
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3617
		}
3618
		if ($wlcfg['mode'] == "hostap") {
3619
			/* add line to script to restore old mac to make hostapd happy */
3620
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3621
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3622
				$if_curmac = get_interface_mac($if);
3623
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3624
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3625
						" link " . escapeshellarg($if_oldmac) . "\n");
3626
				}
3627
			}
3628

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

    
3631
			/* add line to script to restore spoofed mac after running hostapd */
3632
			if ($wl['spoofmac']) {
3633
				$if_curmac = get_interface_mac($if);
3634
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3635
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3636
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3637
				}
3638
			}
3639
		}
3640
	}
3641

    
3642
	fclose($fd_set);
3643

    
3644
	/* Making sure regulatory settings have actually changed
3645
	 * before applying, because changing them requires bringing
3646
	 * down all wireless networks on the interface. */
3647
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3648
	$ifconfig_str = implode($output);
3649
	unset($output);
3650
	$reg_changing = false;
3651

    
3652
	/* special case for the debug country code */
3653
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3654
		$reg_changing = true;
3655
	} elseif ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3656
		$reg_changing = true;
3657
	} elseif ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3658
		$reg_changing = true;
3659
	} elseif ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3660
		$reg_changing = true;
3661
	} elseif ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3662
		$reg_changing = true;
3663
	}
3664

    
3665
	if ($reg_changing) {
3666
		/* set regulatory domain */
3667
		if ($wlcfg['regdomain']) {
3668
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3669
		}
3670

    
3671
		/* set country */
3672
		if ($wlcfg['regcountry']) {
3673
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3674
		}
3675

    
3676
		/* set location */
3677
		if ($wlcfg['reglocation']) {
3678
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3679
		}
3680

    
3681
		$wlregcmd_args = implode(" ", $wlregcmd);
3682

    
3683
		/* build a complete list of the wireless clones for this interface */
3684
		$clone_list = array();
3685
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3686
			$clone_list[] = interface_get_wireless_clone($baseif);
3687
		}
3688
		foreach (config_get_path('wireless/clone', []) as $clone) {
3689
			if ($clone['if'] == $baseif) {
3690
				$clone_list[] = $clone['cloneif'];
3691
			}
3692
		}
3693

    
3694
		/* find which clones are up and bring them down */
3695
		$clones_up = array();
3696
		foreach ($clone_list as $clone_if) {
3697
			$clone_status = get_interface_addresses($clone_if);
3698
			if ($clone_status['status'] == 'up') {
3699
				$clones_up[] = $clone_if;
3700
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3701
			}
3702
		}
3703

    
3704
		/* apply the regulatory settings */
3705
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3706
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3707

    
3708
		/* bring the clones back up that were previously up */
3709
		foreach ($clones_up as $clone_if) {
3710
			interfaces_bring_up($clone_if);
3711

    
3712
			/*
3713
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3714
			 * is in infrastructure mode, and WPA is enabled.
3715
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3716
			 */
3717
			if ($clone_if != $if) {
3718
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3719
				if ((!empty($friendly_if)) &&
3720
				    (config_get_path("interfaces/{$friendly_if}/wireless/mode") == "bss") &&
3721
				    config_path_enabled("interfaces/{$friendly_if}/wireless/wpa")) {
3722
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3723
				}
3724
			}
3725
		}
3726
	}
3727

    
3728
	/* The mode must be specified in a separate command before ifconfig
3729
	 * will allow the mode and channel at the same time in the next.
3730
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3731
	 */
3732
	if ($wlcfg['mode'] == "hostap") {
3733
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3734
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3735
	}
3736

    
3737
	/* configure wireless */
3738
	$wlcmd_args = implode(" ", $wlcmd);
3739
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args);
3740
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3741
	/* Bring the interface up only after setting up all the other parameters. */
3742
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up");
3743
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3744
	fclose($wlan_setup_log);
3745

    
3746
	unset($wlcmd_args, $wlcmd);
3747

    
3748

    
3749
	sleep(1);
3750
	/* execute hostapd and wpa_supplicant if required in shell */
3751
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3752

    
3753
	return 0;
3754

    
3755
}
3756

    
3757
function kill_hostapd($interface) {
3758
	global $g;
3759

    
3760
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3761
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3762
	}
3763
}
3764

    
3765
function kill_wpasupplicant($interface) {
3766
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3767
}
3768

    
3769
function find_dhclient_process($interface) {
3770
	if ($interface) {
3771
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3772
	} else {
3773
		$pid = 0;
3774
	}
3775

    
3776
	return intval($pid);
3777
}
3778

    
3779
function kill_dhclient_process($interface) {
3780
	if (empty($interface) || !does_interface_exist($interface)) {
3781
		return;
3782
	}
3783

    
3784
	$i = 0;
3785
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3786
		/* 3rd time make it die for sure */
3787
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3788
		posix_kill($pid, $sig);
3789
		sleep(1);
3790
		$i++;
3791
	}
3792
	unset($i);
3793
}
3794

    
3795
function find_dhcp6c_process() {
3796
	global $g;
3797

    
3798
	if (isvalidpid("{$g['varrun_path']}/dhcp6c.pid")) {
3799
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c.pid"), " \n");
3800
	} else {
3801
		return(false);
3802
	}
3803

    
3804
	return intval($pid);
3805
}
3806

    
3807
function kill_dhcp6client_process($force, $release = false) {
3808
	global $g;
3809

    
3810
	$i = 0;
3811

    
3812
	/*
3813
	Beware of the following: Reason, the interface may be down, but
3814
	dhcp6c may still be running, it just complains it cannot send
3815
	and carries on. Commented out as will stop the call to kill.
3816

    
3817
	if (empty($interface) || !does_interface_exist($interface)) {
3818
		return;
3819
	}
3820
	*/
3821

    
3822
	/*********** Notes on signals for dhcp6c and this function *************
3823

    
3824
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3825
	a release and waiting for the response that never comes.
3826
	So we need to tell it that the interface is down and to just die quickly
3827
	otherwise a new client may launch and we have duplicate proceses.
3828
	In this case use SIGUSR1.
3829

    
3830
	If we want to exit normally obeying the no release flag then use SIGTERM.
3831
	If we want to exit with a release overiding the no release flag then
3832
	use SIGUSR2.
3833

    
3834
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3835
	exit quickly without sending release signals.
3836

    
3837
	If $Force is set to false and $release is also set to false dhcp6c will
3838
	follow the no-release flag.
3839

    
3840
	If $Force is set to false and $release is true then dhcp6c will send a
3841
	release regardless of the no-release flag.
3842
	***********************************************************************/
3843

    
3844
	if ($force == true) {
3845
		$psig=SIGUSR1;
3846
	} elseif ($release == false) {
3847
		$psig=SIGTERM;
3848
	} else {
3849
		$psig=SIGUSR2;
3850
	}
3851

    
3852
	while ((($pid = find_dhcp6c_process()) != 0) && ($i < 3)) {
3853
		/* 3rd time make it die for sure */
3854
		$sig = ($i == 2 ? SIGKILL : $psig);
3855
		posix_kill($pid, $sig);
3856
		sleep(1);
3857
		$i++;
3858
	}
3859
	/* Clear the RTSOLD script created lock & tidy up */
3860
	unlink_if_exists("/tmp/dhcp6c_lock");
3861
	unlink_if_exists("{$g['varrun_path']}/dhcp6c.pid"); // just in case!
3862
}
3863
function reset_dhcp6client_process() {
3864

    
3865
	$pid = find_dhcp6c_process();
3866

    
3867
	if($pid != 0) {
3868
		posix_kill($pid, SIGHUP);
3869
	}
3870
}
3871

    
3872
function run_dhcp6client_process($interfaces, $debugOption, $noreleaseOption) {
3873
	global $g;
3874

    
3875
	/*
3876
	 * Only run this if the lock does not exist. In theory the lock being
3877
	 * there in this mode means the user has selected dhcp6withoutRA while
3878
	 * a session is active in the other mode.
3879
	 *
3880
	 * It should not happen as the process should have been killed and the
3881
	 * lock deleted.
3882
	 */
3883

    
3884
	if (!file_exists("/tmp/dhcp6c_lock")) {
3885
		kill_dhcp6client_process(true);
3886
		/* Lock it to avoid multiple runs */
3887
		touch("/tmp/dhcp6c_lock");
3888
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
3889
		    "{$noreleaseOption} " .
3890
		    "-c {$g['varetc_path']}/dhcp6c.conf " .
3891
		    "-p {$g['varrun_path']}/dhcp6c.pid " .
3892
		    implode(' ', $interfaces));
3893
		log_error(sprintf(gettext(
3894
		    "Starting DHCP6 client for interfaces %s in DHCP6 without RA mode"),
3895
		    implode(',', $interfaces)));
3896
	}
3897
}
3898

    
3899
function interface_virtual_create($interface, $gateways_status = false) {
3900

    
3901
	/* Fetch gateway status if not passed */
3902
	if (!is_array($gateways_status)) {
3903
		$gateways_status = return_gateways_status(true);
3904
	}
3905

    
3906
	if (interface_is_vlan($interface) != NULL) {
3907
		interface_vlan_configure(interface_is_vlan($interface));
3908
	} elseif (substr($interface, 0, 3) == "gre") {
3909
		interfaces_tunnel_configure(0, $interface, 'gre');
3910
	} elseif (substr($interface, 0, 3) == "gif") {
3911
		interfaces_tunnel_configure(0, $interface, 'gif');
3912
	} elseif (substr($interface, 0, 5) == "ovpns") {
3913
		foreach (config_get_path('openvpn/openvpn-server', []) as $server) {
3914
			if ($interface == "ovpns{$server['vpnid']}") {
3915
				if (!function_exists('openvpn_resync')) {
3916
					require_once('openvpn.inc');
3917
				}
3918
				log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3919
				openvpn_resync('server', $server);
3920
			}
3921
		}
3922
		unset($server);
3923
	} elseif (substr($interface, 0, 5) == "ovpnc") {
3924
		foreach (config_get_path('openvpn/openvpn-client', []) as $client) {
3925
			if ($interface == "ovpnc{$client['vpnid']}") {
3926
				if (!function_exists('openvpn_resync')) {
3927
					require_once('openvpn.inc');
3928
				}
3929
				log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3930
				openvpn_resync('client', $client);
3931
			}
3932
		}
3933
		unset($client);
3934
	} elseif (substr($interface, 0, 5) == "ipsec") {
3935
		foreach (config_get_path('ipsec/phase1', []) as $ph1ent) {
3936
			if ($ph1ent['disabled']) {
3937
				continue;
3938
			}
3939
			interface_ipsec_vti_configure($ph1ent, $gateways_status);
3940
		}
3941
	} elseif (substr($interface, 0, 4) == "lagg") {
3942
		interfaces_lagg_configure($interface);
3943
	} elseif (substr($interface, 0, 6) == "bridge") {
3944
		interfaces_bridge_configure(0, $interface);
3945
	}
3946
}
3947

    
3948
function interface_vlan_mtu_configured($iface) {
3949

    
3950
	$mtu = 0;
3951
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
3952

    
3953
		if ($vlan['vlanif'] != $iface)
3954
			continue;
3955

    
3956
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3957
		$parentinf = convert_real_interface_to_friendly_interface_name($vlan['if']);
3958
		if (!empty($assignedport) && !empty(config_get_path("interfaces/{$assignedport}/mtu"))) {
3959
			/* VLAN MTU */
3960
			$mtu = config_get_path("interfaces/{$assignedport}/mtu");
3961
		} elseif (!empty(config_get_path("interfaces/{$parentinf}/mtu"))) {
3962
			/* Parent MTU */
3963
			$mtu = config_get_path("interfaces/{$parentinf}/mtu");
3964
		}
3965
	}
3966

    
3967
	return $mtu;
3968
}
3969

    
3970
function interface_mtu_wanted_for_pppoe($realif) {
3971

    
3972
	$mtu = 0;
3973
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
3974
		if ($ppp['type'] != "pppoe") {
3975
			continue;
3976
		}
3977

    
3978
		$mtus = array();
3979
		if (!empty($ppp['mtu'])) {
3980
			$mtus = explode(',', $ppp['mtu']);
3981
		}
3982
		$ports = explode(',', $ppp['ports']);
3983

    
3984
		foreach ($ports as $pid => $port) {
3985
			$parentifa = get_parent_interface($port);
3986
			$parentif = $parentifa[0];
3987
			if ($parentif != $realif)
3988
				continue;
3989

    
3990
			// there is an MTU configured on the port in question
3991
			if (!empty($mtus[$pid])) {
3992
				$mtu = intval($mtus[$pid]) + 8;
3993
			// or use the MTU configured on the interface ...
3994
			} else {
3995
				foreach (config_get_path('interfaces', []) as $interface) {
3996
					if ($interface['if'] == $ppp['if'] &&
3997
					    !empty($interface['mtu'])) {
3998
						$mtu = intval($interface['mtu']) + 8;
3999
						break;
4000
					}
4001
				}
4002
			}
4003
		}
4004
	}
4005

    
4006
	return $mtu;
4007
}
4008

    
4009
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
4010
	global $g;
4011
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
4012
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
4013

    
4014
	$wancfg = config_get_path("interfaces/{$interface}");
4015

    
4016
	if (!isset($wancfg['enable'])) {
4017
		return;
4018
	}
4019

    
4020
	$realif = get_real_interface($interface);
4021
	$realhwif_array = get_parent_interface($interface);
4022
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
4023
	$realhwif = $realhwif_array[0];
4024

    
4025
	$mac_if_cfg = $wancfg;
4026
	if (interface_is_vlan($realif)) {
4027
		$mac_if = convert_real_interface_to_friendly_interface_name(
4028
		    $realhwif);
4029
		if (is_array(config_get_path("interfaces/{$mac_if}"))) {
4030
			$mac_if_cfg = config_get_path("interfaces/{$mac_if}");
4031
		} else {
4032
			$mac_if = $interface;
4033
		}
4034
	}
4035

    
4036
	if (!platform_booting() && (substr($realif, 0, 4) != "ovpn") && (substr($realif, 0, 5) != "ipsec")) {
4037
		/* remove all IPv4 and IPv6 addresses */
4038
		$tmpifaces = pfSense_getall_interface_addresses($realif);
4039
		if (is_array($tmpifaces)) {
4040
			foreach ($tmpifaces as $tmpiface) {
4041
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
4042
					if (!is_linklocal($tmpiface)) {
4043
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
4044
					}
4045
				} elseif (strstr($tmpiface, "fe80::1:1")) {
4046
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 fe80::1:1 -alias");
4047
				} else {
4048
					if (is_subnetv4($tmpiface)) {
4049
						$tmpip = explode('/', $tmpiface);
4050
						$tmpip = $tmpip[0];
4051
					} else {
4052
						$tmpip = $tmpiface;
4053
					}
4054
					pfSense_interface_deladdress($realif, $tmpip);
4055
				}
4056
			}
4057
		}
4058

    
4059
		/* only bring down the interface when both v4 and v6 are set to NONE */
4060
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
4061
			interface_bring_down($interface);
4062
		}
4063
	}
4064

    
4065
	$interface_to_check = $realif;
4066
	if (interface_isppp_type($interface)) {
4067
		$interface_to_check = $realhwif;
4068
	}
4069

    
4070
	/* Need to check that the interface exists or not in the case where its coming back from disabled state see #3270 */
4071
	if (!platform_booting() && (in_array(substr($realif, 0, 3), array("gre", "gif")) ||
4072
	    !does_interface_exist($interface_to_check))) {
4073
		interface_virtual_create($interface_to_check);
4074
	}
4075

    
4076
	/* Disable Accepting router advertisements unless specifically requested */
4077
	if ($g['debug']) {
4078
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
4079
	}
4080
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
4081
	{
4082
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
4083
	}
4084
	/* wireless configuration? */
4085
	if (is_array($wancfg['wireless']) && !$linkupevent) {
4086
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
4087
	}
4088

    
4089
	$current_mac = get_interface_mac($realhwif);
4090
	$vendor_mac = get_interface_vendor_mac($realhwif);
4091

    
4092
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
4093
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
4094

    
4095
		interface_set_macaddr($realhwif, $mac_addr);
4096

    
4097
		/* Regenerate link-local address on MAC change.
4098
		 *
4099
		 * Some network devices respond to a DHCPv6 Solicit message only when
4100
		 * the IPv6 source address is consistent with what they expect.
4101
		 *
4102
		 * See https://redmine.pfsense.org/issues/12794 */
4103
		if ($mac_addr != $current_mac) {
4104
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 ifdisabled");
4105
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 " . get_interface_linklocal($interface) . " delete");
4106
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -ifdisabled");
4107
		}
4108
	} else {
4109
		/*
4110
		 * this is not a valid mac address.  generate a
4111
		 * temporary mac address so the machine can get online.
4112
		 */
4113
		echo gettext("Generating new MAC address.");
4114
		$random_mac = generate_random_mac_address();
4115
		interface_set_macaddr($realhwif, $random_mac);
4116
		config_set_path("interfaces/{$mac_if}/spoofmac", $random_mac);
4117
		write_config(sprintf(gettext('The invalid MAC address ' .
4118
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
4119
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
4120
		file_notice("MAC Address altered", sprintf(gettext('The ' .
4121
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
4122
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
4123
		    $random_mac), "Interfaces");
4124
	}
4125

    
4126
	/* media */
4127
	if ($wancfg['media'] || $wancfg['mediaopt']) {
4128
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
4129
		if ($wancfg['media']) {
4130
			$cmd .= " media " . escapeshellarg($wancfg['media']);
4131
		}
4132
		if ($wancfg['mediaopt']) {
4133
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
4134
		}
4135
		mwexec($cmd);
4136
	}
4137

    
4138
	/* Apply hw offloading policies as configured */
4139
	enable_hardware_offloading($interface);
4140

    
4141
	/* invalidate interface/ip/sn cache */
4142
	get_interface_arr(true);
4143
	unset($interface_ip_arr_cache[$realif]);
4144
	unset($interface_sn_arr_cache[$realif]);
4145
	unset($interface_ipv6_arr_cache[$realif]);
4146
	unset($interface_snv6_arr_cache[$realif]);
4147

    
4148
	$tunnelif = substr($realif, 0, 3);
4149

    
4150
	$mtuif = $realif;
4151
	$mtuhwif = $realhwif;
4152

    
4153
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
4154
	if (interface_isppp_type($interface)) {
4155
		$mtuif = $realhwif;
4156
		$mtuhwif_array = get_parent_interface($mtuif);
4157
		$mtuhwif = $mtuhwif_array[0];
4158
	}
4159

    
4160
	$wantedmtu = 0;
4161
	foreach (config_get_path('interfaces', []) as $tmpinterface) {
4162
		if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
4163
			$wantedmtu = $tmpinterface['mtu'];
4164
			break;
4165
		}
4166
	}
4167

    
4168
	/* MTU is not specified for interface, try the pppoe settings. */
4169
	if ($wantedmtu == 0) {
4170
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
4171
	}
4172
	if (($wantedmtu == 0) && (interface_is_vlan($mtuif) != NULL) && interface_isppp_type($interface)) {
4173
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
4174
	}
4175
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gre')) {
4176
		/* set MTU to 1400 for GRE over IPsec */
4177
		if (is_greipsec($mtuif)) {
4178
			$wantedmtu = 1400;
4179
		} else {
4180
			$wantedmtu = 1476;
4181
		}
4182
	}
4183
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gif')) {
4184
		$wantedmtu = 1280;
4185
	}
4186

    
4187
	/* Set the MTU to 1500 if no explicit MTU configured. */
4188
	if ($wantedmtu == 0) {
4189
		$wantedmtu = 1500; /* Default */
4190
	}
4191

    
4192
	if (interface_is_vlan($mtuif) != NULL) {
4193
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4194
		if (!empty($assignedparent) && !empty(config_get_path("interfaces/{$assignedparent}/mtu"))) {
4195
			$parentmtu = config_get_path("interfaces/{$assignedparent}/mtu");
4196
			if ($wancfg['mtu'] > $parentmtu) {
4197
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4198
			}
4199
		}
4200

    
4201
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4202

    
4203
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4204
			$configuredmtu = $parentmtu;
4205
		if ($configuredmtu != 0)
4206
			$mtu = $configuredmtu;
4207
		else
4208
			$mtu = $wantedmtu;
4209

    
4210
		/* Set the parent MTU. */
4211
		if (get_interface_mtu($mtuhwif) < $mtu)
4212
			set_interface_mtu($mtuhwif, $mtu);
4213
		/* Set the VLAN MTU. */
4214
		if (get_interface_mtu($mtuif) != $mtu)
4215
			set_interface_mtu($mtuif, $mtu);
4216
	} elseif (substr($mtuif, 0, 4) == 'lagg') {
4217
		/* LAGG interface must be destroyed and re-created to change MTU */
4218
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4219
			foreach (config_get_path('laggs/lagg', []) as $lagg) {
4220
				if ($lagg['laggif'] == $mtuif) {
4221
					interface_lagg_configure($lagg);
4222
					break;
4223
				}
4224
			}
4225
		}
4226
	} else {
4227
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4228
			pfSense_interface_mtu($mtuif, $wantedmtu);
4229
			set_ipv6routes_mtu($mtuif, $wantedmtu);
4230
		}
4231
	}
4232
	/* XXX: What about gre/gif/.. ? */
4233

    
4234
	if (does_interface_exist($wancfg['if'])) {
4235
		interfaces_bring_up($wancfg['if']);
4236
	}
4237

    
4238
	switch ($wancfg['ipaddr']) {
4239
		case 'dhcp':
4240
			interface_dhcp_configure($interface);
4241
			break;
4242
		case 'pppoe':
4243
		case 'l2tp':
4244
		case 'pptp':
4245
		case 'ppp':
4246
			interface_ppps_configure($interface);
4247
			break;
4248
		default:
4249
			/* XXX: Kludge for now related to #3280 */
4250
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips", "l2t"))) {
4251
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
4252
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
4253
				}
4254
			}
4255
			break;
4256
	}
4257

    
4258
	switch ($wancfg['ipaddrv6']) {
4259
		case 'slaac':
4260
		case 'dhcp6':
4261
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
4262
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
4263
			// handles all non-PPP connections with 'dhcp6usev4iface' set
4264
			log_error(gettext("calling interface_dhcpv6_configure."));
4265
			if ((($wancfg['ipaddrv6'] == 'dhcp6') && !isset($wancfg['dhcp6usev4iface'])) ||
4266
			    (($wancfg['ipaddrv6'] == 'slaac') && !isset($wancfg['slaacusev4iface'])) ||
4267
			    !interface_isppp_type($interface)) {
4268
				interface_dhcpv6_configure($interface, $wancfg);
4269
			}
4270
			break;
4271
		case '6rd':
4272
			interface_6rd_configure($interface, $wancfg);
4273
			break;
4274
		case '6to4':
4275
			interface_6to4_configure($interface, $wancfg);
4276
			break;
4277
		case 'track6':
4278
			interface_track6_configure($interface, $wancfg, $linkupevent);
4279
			break;
4280
		default:
4281
			/* XXX: Kludge for now related to #3280 */
4282
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips", "l2t"))) {
4283
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
4284
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
4285
					// FIXME: Add IPv6 Support to the pfSense module
4286
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
4287
				}
4288
			}
4289
			break;
4290
	}
4291

    
4292
	if (!platform_booting()) {
4293
		link_interface_to_vips($interface, "update");
4294

    
4295
		if ($tunnelif != 'gre') {
4296
			$gre = link_interface_to_tunnelif($interface, 'gre');
4297
			array_walk($gre, 'interface_gre_configure');
4298
		}
4299

    
4300
		if ($tunnelif != 'gif') {
4301
			$gif = link_interface_to_tunnelif($interface, 'gif');
4302
			array_walk($gif, 'interface_gif_configure');
4303
		}
4304

    
4305
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4306
			unset($bridgetmp);
4307
			$bridgetmp = link_interface_to_bridge($interface);
4308
			if (!empty($bridgetmp)) {
4309
				interface_bridge_add_member($bridgetmp, $realif);
4310
			}
4311
		}
4312

    
4313
		$grouptmp = link_interface_to_group($interface);
4314
		if (!empty($grouptmp)) {
4315
			array_walk($grouptmp, 'interface_group_add_member');
4316
		}
4317

    
4318
		if ($interface == "lan") {
4319
			/* make new hosts file */
4320
			system_hosts_generate();
4321
		}
4322

    
4323
		if ($reloadall == true) {
4324

    
4325
			/* reconfigure static routes (kernel may have deleted them) */
4326
			system_routing_configure($interface);
4327

    
4328
			/* reload ipsec tunnels */
4329
			send_event("service reload ipsecdns");
4330

    
4331
			if (config_path_enabled('dnsmasq')) {
4332
				services_dnsmasq_configure();
4333
			}
4334

    
4335
			if (config_path_enabled('unbound')) {
4336
				services_unbound_configure();
4337
			}
4338

    
4339
			/* update dyndns */
4340
			send_event("service reload dyndns {$interface}");
4341
		}
4342
	} 
4343

    
4344
	if (!platform_booting() && (substr($realif, 0, 5) == 'l2tps')) {
4345
		vpn_l2tp_configure();
4346
	};
4347

    
4348
	if (!empty($wancfg['descr'])) {
4349
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4350
	};
4351

    
4352
	interfaces_staticarp_configure($interface);
4353
	return 0;
4354
}
4355

    
4356
function interface_track6_configure($interface, $wancfg, $linkupevent = false) {
4357
	global $g;
4358

    
4359
	if (!is_array($wancfg)) {
4360
		return;
4361
	}
4362

    
4363
	if (!isset($wancfg['enable'])) {
4364
		return;
4365
	}
4366

    
4367
	/* If the interface is not configured via another, exit */
4368
	if (empty($wancfg['track6-interface'])) {
4369
		return;
4370
	}
4371

    
4372
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4373
	$realif = get_real_interface($interface);
4374
	$linklocal = find_interface_ipv6_ll($realif, true);
4375
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4376
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4377
	}
4378

    
4379
	$trackcfg = config_get_path("interfaces/{$wancfg['track6-interface']}");
4380
	if (!isset($trackcfg['enable'])) {
4381
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4382
		return;
4383
	}
4384

    
4385
	$type = $trackcfg['ipaddrv6'];
4386
	switch ($type) {
4387
		case "6to4":
4388
			if ($g['debug']) {
4389
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4390
			}
4391
			interface_track6_6to4_configure($interface, $wancfg);
4392
			break;
4393
		case "6rd":
4394
			if ($g['debug']) {
4395
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4396
			}
4397
			interface_track6_6rd_configure($interface, $wancfg);
4398
			break;
4399
		case "dhcp6":
4400
			if ($linkupevent == true) {
4401
				/*
4402
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4403
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4404
				 *
4405
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4406
				 */
4407
				$pidv6 = find_dhcp6c_process();
4408
				if ($pidv6) {
4409
					posix_kill($pidv6, SIGHUP);
4410
				}
4411
			}
4412
			break;
4413
	}
4414

    
4415
	if ($linkupevent == false && !platform_booting()) {
4416
		if (!function_exists('services_dhcpd_configure')) {
4417
			require_once("services.inc");
4418
		}
4419

    
4420
		/* restart dns servers (defering dhcpd reload) */
4421
		if (config_path_enabled('unbound')) {
4422
			services_unbound_configure(false);
4423
		}
4424
		if (config_path_enabled('dnsmasq')) {
4425
			services_dnsmasq_configure(false);
4426
		}
4427

    
4428
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4429
		services_dhcpd_configure("inet6");
4430
	}
4431

    
4432
	return 0;
4433
}
4434

    
4435
function interface_track6_6rd_configure($interface, $lancfg) {
4436
	global $interface_ipv6_arr_cache;
4437
	global $interface_snv6_arr_cache;
4438

    
4439
	if (!is_array($lancfg)) {
4440
		return;
4441
	}
4442

    
4443
	/* If the interface is not configured via another, exit */
4444
	if (empty($lancfg['track6-interface'])) {
4445
		return;
4446
	}
4447

    
4448
	$wancfg = config_get_path("interfaces/{$lancfg['track6-interface']}");
4449
	if (empty($wancfg)) {
4450
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4451
		return;
4452
	}
4453

    
4454
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4455
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4456
		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']));
4457
		return;
4458
	}
4459
	$hexwanv4 = return_hex_ipv4($ip4address);
4460

    
4461
	/* create the long prefix notation for math, save the prefix length */
4462
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4463
	$rd6prefixlen = $rd6prefix[1];
4464
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4465

    
4466
	/* binary presentation of the prefix for all 128 bits. */
4467
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4468

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

    
4474
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4475
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4476
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4477
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4478
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4479
	/* fill the rest out with zeros */
4480
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4481

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

    
4485
	$lanif = get_real_interface($interface);
4486
	$oip = find_interface_ipv6($lanif);
4487
	if (is_ipaddrv6($oip)) {
4488
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4489
	}
4490
	unset($interface_ipv6_arr_cache[$lanif]);
4491
	unset($interface_snv6_arr_cache[$lanif]);
4492
	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));
4493
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4494

    
4495
	return 0;
4496
}
4497

    
4498
function interface_track6_6to4_configure($interface, $lancfg) {
4499
	global $interface_ipv6_arr_cache;
4500
	global $interface_snv6_arr_cache;
4501

    
4502
	if (!is_array($lancfg)) {
4503
		return;
4504
	}
4505

    
4506
	/* If the interface is not configured via another, exit */
4507
	if (empty($lancfg['track6-interface'])) {
4508
		return;
4509
	}
4510

    
4511
	$wancfg = config_get_path("interfaces/{$lancfg['track6-interface']}");
4512
	if (empty($wancfg)) {
4513
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4514
		return;
4515
	}
4516

    
4517
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4518
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4519
		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']));
4520
		return;
4521
	}
4522
	$hexwanv4 = return_hex_ipv4($ip4address);
4523

    
4524
	/* create the long prefix notation for math, save the prefix length */
4525
	$sixto4prefix = "2002::";
4526
	$sixto4prefixlen = 16;
4527
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4528

    
4529
	/* binary presentation of the prefix for all 128 bits. */
4530
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4531

    
4532
	/* just save the left prefix length bits */
4533
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4534
	/* add the v4 address */
4535
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4536
	/* add the custom prefix id */
4537
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4538
	/* fill the rest out with zeros */
4539
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4540

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

    
4544
	$lanif = get_real_interface($interface);
4545
	$oip = find_interface_ipv6($lanif);
4546
	if (is_ipaddrv6($oip)) {
4547
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4548
	}
4549
	unset($interface_ipv6_arr_cache[$lanif]);
4550
	unset($interface_snv6_arr_cache[$lanif]);
4551
	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));
4552
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4553

    
4554
	return 0;
4555
}
4556

    
4557
function interface_6rd_configure($interface, $wancfg) {
4558
	global $g;
4559

    
4560
	/* because this is a tunnel interface we can only function
4561
	 *	with a public IPv4 address on the interface */
4562

    
4563
	if (!is_array($wancfg)) {
4564
		return;
4565
	}
4566

    
4567
	if (!is_module_loaded('if_stf.ko')) {
4568
		mwexec('/sbin/kldload if_stf.ko');
4569
	}
4570

    
4571
	$wanif = get_real_interface($interface);
4572
	$ip4address = find_interface_ip($wanif);
4573
	if (!is_ipaddrv4($ip4address)) {
4574
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4575
		return false;
4576
	}
4577
	$hexwanv4 = return_hex_ipv4($ip4address);
4578

    
4579
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4580
		$wancfg['prefix-6rd-v4plen'] = 0;
4581
	}
4582

    
4583
	/* create the long prefix notation for math, save the prefix length */
4584
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4585
	$rd6prefixlen = $rd6prefix[1];
4586
	$brgw = explode('.', $wancfg['gateway-6rd']);
4587
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4588
	$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);
4589
	if (strlen($rd6brgw) < 128) {
4590
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4591
	}
4592
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4593
	unset($brgw);
4594
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4595

    
4596
	/* binary presentation of the prefix for all 128 bits. */
4597
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4598

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

    
4606
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4607
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4608

    
4609

    
4610
	/* XXX: need to extend to support variable prefix size for v4 */
4611
	$stfiface = "{$interface}_stf";
4612
	if (does_interface_exist($stfiface)) {
4613
		pfSense_interface_destroy($stfiface);
4614
	}
4615
	$tmpstfiface = pfSense_interface_create2("stf");
4616
	pfSense_interface_rename($tmpstfiface, $stfiface);
4617
	pfSense_interface_flags($stfiface, IFF_LINK2);
4618
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4619
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4620
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4621
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4622
	}
4623
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4624
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4625
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4626
	} elseif ($parentmtu > 1300) {
4627
		set_interface_mtu($stfiface, $parentmtu - 20);
4628
	}
4629
	if ($g['debug']) {
4630
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4631
	}
4632

    
4633
	/* write out a default router file */
4634
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4635
	unlink_if_exists("{$g['tmp_path']}/{$wanif}_routerv6.last");
4636
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4637

    
4638
	$ip4gateway = get_interface_gateway($interface);
4639
	if (is_ipaddrv4($ip4gateway)) {
4640
		route_add_or_change($wancfg['gateway-6rd'], $ip4gateway);
4641
	}
4642

    
4643
	/* configure dependent interfaces */
4644
	if (!platform_booting()) {
4645
		link_interface_to_track6($interface, "update");
4646
	}
4647

    
4648
	return 0;
4649
}
4650

    
4651
function interface_6to4_configure($interface, $wancfg) {
4652
	global $g;
4653

    
4654
	/* because this is a tunnel interface we can only function
4655
	 *	with a public IPv4 address on the interface */
4656

    
4657
	if (!is_array($wancfg)) {
4658
		return;
4659
	}
4660

    
4661
	$wanif = get_real_interface($interface);
4662
	$ip4address = find_interface_ip($wanif);
4663
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4664
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4665
		return false;
4666
	}
4667

    
4668
	/* create the long prefix notation for math, save the prefix length */
4669
	$stfprefixlen = 16;
4670
	$stfprefix = Net_IPv6::uncompress("2002::");
4671
	$stfarr = explode(":", $stfprefix);
4672
	$v4prefixlen = "0";
4673

    
4674
	/* we need the hex form of the interface IPv4 address */
4675
	$ip4arr = explode(".", $ip4address);
4676
	$hexwanv4 = "";
4677
	foreach ($ip4arr as $octet) {
4678
		$hexwanv4 .= sprintf("%02x", $octet);
4679
	}
4680

    
4681
	/* we need the hex form of the broker IPv4 address */
4682
	$ip4arr = explode(".", "192.88.99.1");
4683
	$hexbrv4 = "";
4684
	foreach ($ip4arr as $octet) {
4685
		$hexbrv4 .= sprintf("%02x", $octet);
4686
	}
4687

    
4688
	/* binary presentation of the prefix for all 128 bits. */
4689
	$stfprefixbin = "";
4690
	foreach ($stfarr as $element) {
4691
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4692
	}
4693
	/* just save the left prefix length bits */
4694
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4695

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

    
4700
	/* for the local subnet too. */
4701
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4702
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4703

    
4704
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4705
	$stfbrarr = array();
4706
	$stfbrbinarr = array();
4707
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4708
	foreach ($stfbrbinarr as $bin) {
4709
		$stfbrarr[] = dechex(bindec($bin));
4710
	}
4711
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4712

    
4713
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4714
	$stflanarr = array();
4715
	$stflanbinarr = array();
4716
	$stflanbinarr = str_split($stflanbin, 16);
4717
	foreach ($stflanbinarr as $bin) {
4718
		$stflanarr[] = dechex(bindec($bin));
4719
	}
4720
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4721
	$stflanarr[7] = 1;
4722

    
4723
	/* setup the stf interface */
4724
	if (!is_module_loaded("if_stf")) {
4725
		mwexec("/sbin/kldload if_stf.ko");
4726
	}
4727
	$stfiface = "{$interface}_stf";
4728
	if (does_interface_exist($stfiface)) {
4729
		pfSense_interface_destroy($stfiface);
4730
	}
4731
	$tmpstfiface = pfSense_interface_create2("stf");
4732
	pfSense_interface_rename($tmpstfiface, $stfiface);
4733
	pfSense_interface_flags($stfiface, IFF_LINK2);
4734
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4735

    
4736
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4737
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4738
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4739
	} elseif ($parentmtu > 1300) {
4740
		set_interface_mtu($stfiface, $parentmtu - 20);
4741
	}
4742
	if ($g['debug']) {
4743
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4744
	}
4745

    
4746
	/* write out a default router file */
4747
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4748
	unlink_if_exists("{$g['tmp_path']}/{$wanif}_routerv6.last");
4749
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4750

    
4751
	$ip4gateway = get_interface_gateway($interface);
4752
	if (is_ipaddrv4($ip4gateway)) {
4753
		route_add_or_change("192.88.99.1", $ip4gateway);
4754
	}
4755

    
4756
	if (!platform_booting()) {
4757
		link_interface_to_track6($interface, "update");
4758
	}
4759

    
4760
	return 0;
4761
}
4762

    
4763
function interface_dhcpv6_configure($ifconf, $ifcfg, $destroy = false) {
4764
	global $g;
4765

    
4766
	$dhcp6cconf = "";
4767
	$id = "0";
4768
	$dhcp6cinterfaces = array();
4769
	$dhcp6cifs_descr = array();
4770
	$dhcp6crealifs = array();
4771
	$debugOption = "-d";
4772
	$noreleaseOption = "";
4773

    
4774
	if (!empty(config_get_path('system/global-v6duid'))) {
4775
		// Write the DUID file
4776
		if(!write_dhcp6_duid(config_get_path('system/global-v6duid'))) {
4777
		    log_error(gettext("Failed to write user DUID file!"));
4778
		}
4779
	}
4780

    
4781
	foreach (config_get_path('interfaces', []) as $interface => $wancfg) {
4782
		$wanif = get_real_interface($interface, "inet6");
4783

    
4784
		if (($ifconf == $interface) && $destroy) {
4785
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
4786
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh");
4787
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$wanif}_script.sh");
4788
			continue;
4789
		}
4790

    
4791
		if (!isset($wancfg['enable']) || (($ifconf == $interface) && $destroy) ||
4792
		    (($wancfg['ipaddrv6'] != 'dhcp6') && ($wancfg['ipaddrv6'] != 'slaac'))) {
4793
			continue;
4794
		}
4795

    
4796
		$dhcp6cinterfaces[$interface] = $wancfg;
4797

    
4798
		if (config_path_enabled('system','dhcp6debug')) {
4799
			$debugOption = "-D";
4800
		}
4801
		if (config_path_enabled('system','dhcp6norelease')) {
4802
			$noreleaseOption = "-n";
4803
		}
4804

    
4805
		/* accept router advertisements for this interface                 */
4806
		/* Moved to early in the function as sometimes interface not ready */
4807
		/* RTSOLD fails as interface does not accept .....                 */
4808

    
4809
		log_error("Accept router advertisements on interface {$wanif} ");
4810
		mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4811

    
4812
		if ($wancfg['adv_dhcp6_config_file_override']) {
4813
			// DHCP6 Config File Override
4814
			$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4815
		} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4816
			// DHCP6 Config File Advanced
4817
			$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4818
		} else {
4819
			// DHCP6 Config File Basic
4820
			$dhcp6cconf .= "interface {$wanif} {\n";
4821

    
4822
			/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4823
			if ($wancfg['ipaddrv6'] == "slaac") {
4824
				$dhcp6cconf .= "\tinformation-only;\n";
4825
				$dhcp6cconf .= "\trequest domain-name-servers;\n";
4826
				$dhcp6cconf .= "\trequest domain-name;\n";
4827
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4828
				$dhcp6cconf .= "};\n";
4829
			} else {
4830
				$trackiflist = array();
4831
				$iflist = link_interface_to_track6($interface);
4832
				foreach ($iflist as $ifname => $ifcfg) {
4833
					if (is_numeric($ifcfg['track6-prefix-id'])) {
4834
						$trackiflist[$ifname] = $ifcfg;
4835
					}
4836
				}
4837

    
4838
				/* skip address request if this is set */
4839
				if (!isset($wancfg['dhcp6prefixonly'])) {
4840
					$dhcp6cconf .= "\tsend ia-na {$id};\t# request stateful address\n";
4841
				}
4842
				if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4843
					$dhcp6cconf .= "\tsend ia-pd {$id};\t# request prefix delegation\n";
4844
				}
4845

    
4846
				$dhcp6cconf .= "\trequest domain-name-servers;\n";
4847
				$dhcp6cconf .= "\trequest domain-name;\n";
4848

    
4849
				/*
4850
				 * dhcp6c will run different scripts depending on
4851
				 * whether dhcpwithoutra is set or unset.
4852
				 */
4853
				if (isset($wancfg['dhcp6withoutra'])) {
4854
					$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4855
				} else {
4856
					$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4857
				}
4858
				$dhcp6cconf .= "};\n";
4859

    
4860
				if (!isset($wancfg['dhcp6prefixonly'])) {
4861
					$dhcp6cconf .= "id-assoc na {$id} { };\n";
4862
				}
4863

    
4864
				if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4865
					/* Setup the prefix delegation */
4866
					$dhcp6cconf .= "id-assoc pd {$id} {\n";
4867
					$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4868
					if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4869
						$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4870
					}
4871
					foreach ($trackiflist as $friendly => $ifcfg) {
4872
						if ($g['debug']) {
4873
							log_error("setting up $interface - {$ifcfg['track6-prefix-id']}");
4874
						}
4875
						$realif = get_real_interface($friendly);
4876
						$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4877
						$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4878
						$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4879
						$dhcp6cconf .= "\t};\n";
4880
					}
4881
					unset($preflen, $iflist, $ifcfg, $ifname);
4882
					$dhcp6cconf .= "};\n\n";
4883
				}
4884
				unset($trackiflist);
4885
			}
4886
			$id++;
4887
		}
4888

    
4889
		/*************** Script Debug Logging ***************************
4890
		Both dhcp6 scripts now have a logging message built in.
4891
		These logging messages ONLY appear if dhcp6c debug logging is set.
4892
		The logging messages appear in the dhcp section of the logs,
4893
		not in system.
4894

    
4895
		These scripts now also take advantage of the REASON= env vars
4896
		supplied by dhcp6c.
4897
		****************************************************************/
4898

    
4899
		/* Script create for dhcp6withoutRA mode */
4900
		/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
4901
		$dhcp6cscriptwithoutra = "#!/bin/sh\n";
4902
		$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4903
		$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4904
		$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4905
		$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
4906
		// Need to pass params to  the final script
4907
		$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4908
		$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4909
		$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
4910
		$dhcp6cscriptwithoutra .= "case \$REASON in\n";
4911
		$dhcp6cscriptwithoutra .= "REQUEST)\n";
4912
		$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
4913
		$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -M {$g['varetc_path']}/rtsold_{$wanif}_script.sh -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
4914
		if ($debugOption == '-D') {
4915
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rtsold\"\n";
4916
		}
4917
		$dhcp6cscriptwithoutra .= ";;\n";
4918
		$dhcp6cscriptwithoutra .= "REBIND)\n";
4919
		if ($debugOption == '-D') {
4920
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4921
		}
4922
		$dhcp6cscriptwithoutra .= ";;\n";
4923
		if (isset($wancfg['dhcp6norelease'])) {
4924
			$dhcp6cscriptwithoutra .= "EXIT)\n";
4925
		} else {
4926
			$dhcp6cscriptwithoutra .= "RELEASE)\n";
4927
		}
4928
		if ($debugOption == '-D') {
4929
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4930
		}
4931
		$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4932
		$dhcp6cscriptwithoutra .= ";;\n";
4933
		$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
4934
		if ($debugOption == '-D') {
4935
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4936
		}
4937
		$dhcp6cscriptwithoutra .= "esac\n";
4938
		if (!@file_put_contents(
4939
		    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4940
		    $dhcp6cscriptwithoutra)) {
4941
			printf("Error: cannot open " .
4942
			    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
4943
			    "interface_dhcpv6_configure() for writing.\n");
4944
			unset($dhcp6cscriptwithoutra);
4945
			return 1;
4946
		}
4947

    
4948
		@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh", 0755);
4949

    
4950
		/*
4951
		 * Dual mode wan_dhcp6c script with variations depending on node
4952
		 * dhcp6 will run the wan ipv6 configure
4953
		 */
4954
		$dhcp6cscript  = "#!/bin/sh\n";
4955
		$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
4956
		if (!isset($wancfg['dhcp6withoutra'])) {
4957
			$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
4958
			$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
4959
			$dhcp6cscript .= "case \$REASON in\n";
4960
			$dhcp6cscript .= "REBIND)\n";
4961
			if ($debugOption == '-D') {
4962
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4963
			}
4964
			$dhcp6cscript .= ";;\n";
4965
			$dhcp6cscript .= "REQUEST|";
4966
			if (isset($wancfg['dhcp6norelease'])) {
4967
				$dhcp6cscript .= "EXIT)\n";
4968
			} else {
4969
				$dhcp6cscript .= "RELEASE)\n";
4970
			}
4971
			if ($debugOption == '-D') {
4972
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c RELEASE, REQUEST or EXIT on {$wanif} running rc.newwanipv6\"\n";
4973
			}
4974
			$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4975
			$dhcp6cscript .= ";;\n";
4976
			$dhcp6cscript .= "RENEW|INFO)\n";
4977
			if ($debugOption == '-D') {
4978
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4979
			}
4980
			$dhcp6cscript .= "esac\n";
4981
			$rtsold_ra_ifs[] = $wanif;
4982
		} else {
4983
			// Need to get the parameters from the dhcp6cwithoutRA run
4984
			$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
4985
			$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
4986
			$dhcp6cscript .= "/bin/sleep 1\n";
4987
			$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4988
		}
4989

    
4990
		/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
4991
		if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
4992
			printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
4993
			unset($dhcp6cscript);
4994
			return 1;
4995
		}
4996
		unset($dhcp6cscript);
4997
		@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
4998
	}
4999

    
5000
	if (!empty($dhcp6cinterfaces)) {
5001
		/* wide-dhcp6c works for now. */
5002
		if (!@file_put_contents("{$g['varetc_path']}/dhcp6c.conf", $dhcp6cconf)) {
5003
			printf("Error: cannot open dhcp6c.conf in interface_dhcpv6_configure() for writing.\n");
5004
			return 1;
5005
		}
5006
		foreach ($dhcp6cinterfaces as $interface => $wancfg) {
5007
			$dhcp6cifs_descr[] = $interface . '(' . $wancfg['if'] . ')';
5008
			$dhcp6crealifs[] = $wancfg['if'];
5009
		}
5010
		$dhcp6cdescr = implode(',', $dhcp6cifs_descr);
5011
		$dhcp6cifs = implode(' ', $dhcp6crealifs);
5012
		foreach ($dhcp6cinterfaces as $interface => $wancfg) {
5013
			$wanif = get_real_interface($interface, "inet6");
5014

    
5015
			$rtsoldscript_header = <<<EOD
5016
#!/bin/sh
5017
# This shell script launches dhcp6c and configured gateways for this interface.
5018
if [ -n "\$2" ]; then
5019
	if [ -n "$(echo \$2 | /usr/bin/grep '^fe80')" ]; then
5020
		echo \$2\%{$wanif} > {$g['tmp_path']}/{$wanif}_routerv6
5021
		/bin/rm -f {$g['tmp_path']}/{$wanif}_routerv6.last
5022
		echo \$2\%{$wanif} > {$g['tmp_path']}/{$wanif}_defaultgwv6
5023
	else
5024
		echo \$2 > {$g['tmp_path']}/{$wanif}_routerv6
5025
		/bin/rm -f {$g['tmp_path']}/{$wanif}_routerv6.last
5026
		echo \$2 > {$g['tmp_path']}/{$wanif}_defaultgwv6
5027
	fi
5028
	/usr/bin/logger -t rtsold "Received RA specifying route \$2 for interface {$interface}({$wanif})"
5029
fi
5030

    
5031
EOD;
5032

    
5033
			/* non ipoe Process */
5034
			$rtsoldscript = $rtsoldscript_header;
5035
			if (!isset($wancfg['dhcp6withoutra'])) {
5036
				/*
5037
				 * We only want this script to run once, and if it runs twice
5038
				 * then do not launch dhcp6c again, this only happens if
5039
				 * dhcpwithoutra is not set.
5040
				 *
5041
				 * Check for a lock file, trying to prevent multiple instances
5042
				 * of dhcp6c being launched
5043
				 */
5044
				$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_lock ]; then\n";
5045
				/*
5046
				 * Create the lock file, trying to prevent multiple instances
5047
				 * of dhcp6c being launched
5048
				 */
5049
				$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_lock\n";
5050
				$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c.pid ]; then\n";
5051
				$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c.pid\n";
5052
				$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c.pid\n";
5053
				$rtsoldscript .= "\t\t/bin/sleep 1\n";
5054
				$rtsoldscript .= "\tfi\n";
5055
				$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
5056
				    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c.conf " .
5057
				    "-p {$g['varrun_path']}/dhcp6c.pid {$dhcp6cifs}\n";
5058
				$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interfaces {$dhcp6cdescr}\"\n";
5059
				$rtsoldscript .= "else\n";
5060
				$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
5061
				$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c.pid\")\n";
5062
				$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
5063
				$rtsoldscript .= "fi\n";
5064
			} else {
5065
				/*
5066
				 * The script needs to run in dhcp6withoutra mode as RA may
5067
				 * not have been received, or there can be a delay with
5068
				 * certain ISPs
5069
				 */
5070
				$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
5071
				$rtsoldscript .= "/bin/sleep 1\n";
5072
			}
5073

    
5074
			/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5075
			if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
5076
				printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
5077
				return 1;
5078
			}
5079
			unset($rtsoldscript);
5080
			@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
5081
		}
5082

    
5083
		$realif = get_real_interface($ifconf, "inet6");
5084
		if (isvalidpid("{$g['varrun_path']}/rtsold_{$realif}.pid")) {
5085
			killbypid("{$g['varrun_path']}/rtsold_{$realif}.pid");
5086
			log_error("Killing running rtsold process");
5087
			sleep(2);
5088
		}
5089

    
5090
		if (file_exists("{$g['tmp_path']}/dhcp6c_ifs")) {
5091
			$dhcp6crealifs_run = unserialize(file_get_contents("{$g['tmp_path']}/dhcp6c_ifs"));
5092
		} else {
5093
			$dhcp6crealifs_run = array();
5094
		}
5095

    
5096
		if (($dhcp6crealifs != $dhcp6crealifs_run) || $destroy) {
5097
			kill_dhcp6client_process(false);
5098
			run_dhcp6client_process($dhcp6crealifs, $debugOption, $noreleaseOption);
5099
			file_put_contents("{$g['tmp_path']}/dhcp6c_ifs", serialize($dhcp6crealifs));
5100
			$dhcp6c_restarted = true;
5101
			if ($destroy) {
5102
				$track6 = link_interface_to_track6($ifconf);
5103
				if (is_array($track6) && !empty($track6)) {
5104
					/* remove stale track interfaces IP */
5105
					foreach (array_keys($track6) as $tr6if) {
5106
						interface_reconfigure($tr6if, true);
5107
					}
5108
				}
5109
			}
5110
		}
5111

    
5112
		if (isset($ifcfg['dhcp6withoutra']) && !$dhcp6c_restarted) {
5113
			/*
5114
			 * Start dhcp6c here if we don't want to wait for ra - calls
5115
			 * separate function
5116
			 *
5117
			 * In this mode dhcp6c launches rtsold via its script. RTSOLD
5118
			 * will then run the configure on receipt of the RA.
5119
			 *
5120
			 * Already started. interface_dhcpv6_configure() appears to get
5121
			 * called multiple times.
5122
			 *
5123
			 * Taking the interface down or releasing will kill the client.
5124
			 */
5125

    
5126
			/*
5127
			 * If the interface is being brought up, wait for the
5128
			 * interface to configure accept RA before launching.
5129
			 * Otherwise it is not ready to accept and will fail.
5130
			 */
5131
			sleep(3);
5132
			if (file_exists("/tmp/dhcp6c_lock")) {
5133
				reset_dhcp6client_process();
5134
			}
5135
		} elseif (!$destroy) {
5136
			/*
5137
			 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
5138
			 * ( it does not background, it exits! ) It will launch dhcp6c
5139
			 * if dhcpwihtoutra is not set
5140
			 */
5141
			log_error("Starting rtsold process on {$ifconf}({$realif})");
5142
			sleep(2);
5143
			mwexec("/usr/sbin/rtsold -1 " .
5144
			    "-p {$g['varrun_path']}/rtsold_{$realif}.pid " .
5145
			    "-M {$g['varetc_path']}/rtsold_{$realif}_script.sh " .
5146
			    "-O {$g['varetc_path']}/rtsold_{$realif}_script.sh " .
5147
			    $realif);
5148
		}
5149
	} else {
5150
		kill_dhcp6client_process(true);
5151
		unlink_if_exists("{$g['varetc_path']}/dhcp6c.conf");
5152
		unlink_if_exists("{$g['tmp_path']}/dhcp6c_ifs");
5153
	}
5154

    
5155
	/*
5156
	 * NOTE: will be called from rtsold invoked script
5157
	 * link_interface_to_track6($interface, "update");
5158
	 */
5159

    
5160
	return 0;
5161
}
5162

    
5163
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5164
	global $g;
5165

    
5166
	$send_options = "";
5167
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
5168
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
5169
		foreach ($options as $option) {
5170
			$send_options .= "\tsend " . trim($option) . ";\n";
5171
		}
5172
	}
5173

    
5174
	$request_options = "";
5175
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5176
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5177
		foreach ($options as $option) {
5178
			$request_options .= "\trequest " . trim($option) . ";\n";
5179
		}
5180
	}
5181

    
5182
	$information_only = "";
5183
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5184
		$information_only = "\tinformation-only;\n";
5185
	}
5186

    
5187
	if (isset($wancfg['dhcp6withoutra'])) {
5188
		$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\";\n";
5189
	} else {
5190
		$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5191
	}
5192
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5193
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5194
	}
5195

    
5196
	$interface_statement  = "interface";
5197
	$interface_statement .= " {$wanif}";
5198
	$interface_statement .= " {\n";
5199
	$interface_statement .= "$send_options";
5200
	$interface_statement .= "$request_options";
5201
	$interface_statement .= "$information_only";
5202
	$interface_statement .= "$script";
5203
	$interface_statement .= "};\n";
5204

    
5205
	$id_assoc_statement_address = "";
5206
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5207
		$id_assoc_statement_address .= "id-assoc";
5208
		$id_assoc_statement_address .= " na";
5209
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5210
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5211
		}
5212
		$id_assoc_statement_address .= " { ";
5213

    
5214
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5215
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5216
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5217
			$id_assoc_statement_address .= "\n\taddress";
5218
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5219
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5220
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5221
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5222
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5223
			}
5224
			$id_assoc_statement_address .= ";\n";
5225
		}
5226

    
5227
		$id_assoc_statement_address .= "};\n";
5228
	}
5229

    
5230
	$id_assoc_statement_prefix = "";
5231
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5232
		$id_assoc_statement_prefix .= "id-assoc";
5233
		$id_assoc_statement_prefix .= " pd";
5234
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5235
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5236
		}
5237
		$id_assoc_statement_prefix .= " { ";
5238

    
5239
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5240
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5241
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5242
			$id_assoc_statement_prefix .= "\n\tprefix";
5243
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5244
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5245
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5246
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5247
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5248
			}
5249
			$id_assoc_statement_prefix .= ";";
5250
		}
5251

    
5252
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
5253
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
5254
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
5255
			$id_assoc_statement_prefix .= " {$realif}";
5256
			$id_assoc_statement_prefix .= " {\n";
5257
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
5258
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
5259
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
5260
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
5261
			}
5262
			$id_assoc_statement_prefix .= "\t};";
5263
		}
5264

    
5265
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5266
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5267
			$id_assoc_statement_prefix .= "\n";
5268
		}
5269

    
5270
		$id_assoc_statement_prefix .= "};\n";
5271
	}
5272

    
5273
	$authentication_statement = "";
5274
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
5275
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
5276
		$authentication_statement .= "authentication";
5277
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
5278
		$authentication_statement .= " {\n";
5279
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
5280
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
5281
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
5282
		}
5283
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
5284
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
5285
		}
5286
		$authentication_statement .= "};\n";
5287
	}
5288

    
5289
	$key_info_statement = "";
5290
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5291
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5292
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5293
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5294
		$key_info_statement .= "keyinfo";
5295
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5296
		$key_info_statement .= " {\n";
5297
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5298
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5299
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5300
		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'])) {
5301
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5302
		}
5303
		$key_info_statement .= "};\n";
5304
	}
5305

    
5306
	$dhcp6cconf  = $interface_statement;
5307
	$dhcp6cconf .= $id_assoc_statement_address;
5308
	$dhcp6cconf .= $id_assoc_statement_prefix;
5309
	$dhcp6cconf .= $authentication_statement;
5310
	$dhcp6cconf .= $key_info_statement;
5311

    
5312
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5313

    
5314
	return $dhcp6cconf;
5315
}
5316

    
5317

    
5318
function DHCP6_Config_File_Override($wancfg, $wanif) {
5319

    
5320
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5321

    
5322
	if ($dhcp6cconf === false) {
5323
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5324
		return '';
5325
	} else {
5326
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5327
	}
5328
}
5329

    
5330

    
5331
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5332

    
5333
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5334

    
5335
	return $dhcp6cconf;
5336
}
5337

    
5338

    
5339
function interface_dhcp_configure($interface) {
5340
	global $g, $vlanprio_values;
5341

    
5342
	$ifcfg = config_get_path("interfaces/{$interface}");
5343
	if (empty($ifcfg)) {
5344
		$ifcfg = array();
5345
	}
5346

    
5347
	$dhclientconf_vlantag = "";
5348
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5349
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5350
	}
5351

    
5352
	/* generate dhclient_wan.conf */
5353
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5354
	if (!$fd) {
5355
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5356
		return 1;
5357
	}
5358

    
5359
	if ($ifcfg['dhcphostname']) {
5360
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5361
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5362
	} else {
5363
		$dhclientconf_hostname = "";
5364
	}
5365

    
5366
	$realif = get_real_interface($interface);
5367
	if (empty($realif)) {
5368
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5369
		return 0;
5370
	}
5371
	$dhclientconf = "";
5372

    
5373
	$dhclientconf .= <<<EOD
5374
interface "{$realif}" {
5375
	supersede interface-mtu 0;
5376
	timeout 60;
5377
	retry 15;
5378
	select-timeout 0;
5379
	initial-interval 1;
5380
	{$dhclientconf_vlantag}
5381
	{$dhclientconf_hostname}
5382
	script "/usr/local/sbin/pfSense-dhclient-script";
5383
EOD;
5384

    
5385
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5386
		$dhclientconf .= <<<EOD
5387

    
5388
	reject {$ifcfg['dhcprejectfrom']};
5389
EOD;
5390
	}
5391
	$dhclientconf .= <<<EOD
5392

    
5393
}
5394

    
5395
EOD;
5396

    
5397
	// DHCP Config File Advanced
5398
	if ($ifcfg['adv_dhcp_config_advanced']) {
5399
		$dhclientconf = DHCP_Config_File_Advanced($ifcfg, $realif);
5400
	}
5401

    
5402
	if (is_ipaddr($ifcfg['alias-address'])) {
5403
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5404
		$dhclientconf .= <<<EOD
5405
alias {
5406
	interface "{$realif}";
5407
	fixed-address {$ifcfg['alias-address']};
5408
	option subnet-mask {$subnetmask};
5409
}
5410

    
5411
EOD;
5412
	}
5413

    
5414
	// DHCP Config File Override
5415
	if ($ifcfg['adv_dhcp_config_file_override']) {
5416
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5417
	}
5418

    
5419
	fwrite($fd, $dhclientconf);
5420
	fclose($fd);
5421

    
5422
	/* bring wan interface up before starting dhclient */
5423
	if ($realif) {
5424
		interfaces_bring_up($realif);
5425
	}
5426

    
5427
	/* Make sure dhclient is not running */
5428
	kill_dhclient_process($realif);
5429

    
5430
	/* fire up dhclient */
5431
	mwexec("/sbin/dhclient -c {$g['varetc_path']}/dhclient_{$interface}.conf -p {$g['varrun_path']}/dhclient.{$realif}.pid {$realif} > {$g['tmp_path']}/{$realif}_output 2> {$g['tmp_path']}/{$realif}_error_output");
5432

    
5433
	return 0;
5434
}
5435

    
5436
function DHCP_Config_File_Advanced($ifcfg, $realif) {
5437

    
5438
	$hostname = "";
5439
	if ($ifcfg['dhcphostname'] != '') {
5440
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5441
	}
5442

    
5443
	/* DHCP Protocol Timings */
5444
	$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");
5445
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5446
		$pt_variable = "{$Protocol_Timing}";
5447
		${$pt_variable} = "";
5448
		if ($ifcfg[$Protocol_Timing] != "") {
5449
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5450
		}
5451
	}
5452

    
5453
	$send_options = "";
5454
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5455
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5456
		foreach ($options as $option) {
5457
			$send_options .= "\tsend " . trim($option) . ";\n";
5458
		}
5459
	}
5460

    
5461
	$request_options = "";
5462
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5463
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5464
	}
5465

    
5466
	$required_options = "";
5467
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5468
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5469
	}
5470

    
5471
	$option_modifiers = "";
5472
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5473
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5474
		foreach ($modifiers as $modifier) {
5475
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5476
		}
5477
	}
5478

    
5479
	$dhclientconf  = "interface \"{$realif}\" {\n";
5480
	$dhclientconf .= "\n";
5481
	$dhclientconf .= "\tsupersede interface-mtu 0;\n";
5482
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5483
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5484
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5485
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5486
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5487
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5488
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5489
	$dhclientconf .= "\n";
5490
	$dhclientconf .= "# DHCP Protocol Options\n";
5491
	$dhclientconf .= "{$hostname}";
5492
	$dhclientconf .= "{$send_options}";
5493
	$dhclientconf .= "{$request_options}";
5494
	$dhclientconf .= "{$required_options}";
5495
	$dhclientconf .= "{$option_modifiers}";
5496
	$dhclientconf .= "\n";
5497
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5498
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5499
	}
5500
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5501
	$dhclientconf .= "}\n";
5502

    
5503
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5504

    
5505
	return $dhclientconf;
5506
}
5507

    
5508
function DHCP_Config_Option_Split($option_string) {
5509
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5510
	return $matches ? $matches[0] : [];
5511
}
5512

    
5513
function DHCP_Config_File_Override($ifcfg, $realif) {
5514

    
5515
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5516

    
5517
	if ($dhclientconf === false) {
5518
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5519
		return '';
5520
	} else {
5521
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5522
	}
5523
}
5524

    
5525

    
5526
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5527

    
5528
	/* Apply Interface Substitutions */
5529
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5530

    
5531
	/* Apply Hostname Substitutions */
5532
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5533

    
5534
	/* Arrays of MAC Address Types, Cases, Delimiters */
5535
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5536
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5537
	$various_mac_cases      = array("U", "L");
5538
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5539

    
5540
	/* Apply MAC Address Substitutions */
5541
	foreach ($various_mac_types as $various_mac_type) {
5542
		foreach ($various_mac_cases as $various_mac_case) {
5543
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5544

    
5545
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5546
				if ($res !== false) {
5547

    
5548
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5549
					if ("$various_mac_case" == "U") {
5550
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5551
					}
5552
					if ("$various_mac_case" == "L") {
5553
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5554
					}
5555

    
5556
					if ("$various_mac_type" == "mac_addr_hex") {
5557
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5558
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5559
						$dhcpclientconf_mac_hex = "";
5560
						$delimiter = "";
5561
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5562
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5563
							$delimiter = ":";
5564
						}
5565
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5566
					}
5567

    
5568
					/* MAC Address Delimiter Substitutions */
5569
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5570

    
5571
					/* Apply MAC Address Substitutions */
5572
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5573
				}
5574
			}
5575
		}
5576
	}
5577

    
5578
	return $dhclientconf;
5579
}
5580

    
5581
function interfaces_group_setup() {
5582
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $groupar) {
5583
		interface_group_setup($groupar);
5584
	}
5585

    
5586
	return;
5587
}
5588

    
5589
function interface_group_setup(&$groupname /* The parameter is an array */) {
5590
	if (!is_array($groupname)) {
5591
		return;
5592
	}
5593
	$members = explode(" ", $groupname['members']);
5594
	foreach ($members as $ifs) {
5595
		$realif = get_real_interface($ifs);
5596
		if ($realif && does_interface_exist($realif)) {
5597
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5598
		}
5599
	}
5600

    
5601
	return;
5602
}
5603

    
5604
function is_interface_group($if) {
5605
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $groupentry) {
5606
		if ($groupentry['ifname'] === $if) {
5607
			return true;
5608
		}
5609
	}
5610

    
5611
	return false;
5612
}
5613

    
5614
function interface_group_add_member($interface, $groupname) {
5615
	$interface = get_real_interface($interface);
5616
	if (does_interface_exist($interface)) {
5617
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5618
	}
5619
}
5620

    
5621
/* COMPAT Function */
5622
function convert_friendly_interface_to_real_interface_name($interface) {
5623
	return get_real_interface($interface);
5624
}
5625

    
5626
/* COMPAT Function */
5627
function get_real_wan_interface($interface = "wan") {
5628
	return get_real_interface($interface);
5629
}
5630

    
5631
/* COMPAT Function */
5632
function get_current_wan_address($interface = "wan") {
5633
	return get_interface_ip($interface);
5634
}
5635

    
5636
/*
5637
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5638
 */
5639
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5640

    
5641
	/* XXX: For speed reasons reference directly the interface array */
5642
	init_config_arr(array('interfaces'));
5643
	$ifdescrs = config_get_path('interfaces');
5644
	//$ifdescrs = get_configured_interface_list(true);
5645

    
5646
	foreach ($ifdescrs as $if => $ifname) {
5647
		if ($if == $interface || $ifname['if'] == $interface) {
5648
			return $if;
5649
		}
5650

    
5651
		if (get_real_interface($if) == $interface) {
5652
			return $if;
5653
		}
5654

    
5655
		if ($checkparent == false) {
5656
			continue;
5657
		}
5658

    
5659
		$int = get_parent_interface($if, true);
5660
		if (is_array($int)) {
5661
			foreach ($int as $iface) {
5662
				if ($iface == $interface) {
5663
					return $if;
5664
				}
5665
			}
5666
		}
5667
	}
5668

    
5669
	if ($interface == "enc0") {
5670
		return 'IPsec';
5671
	}
5672
}
5673

    
5674
/* attempt to resolve interface to friendly descr */
5675
function convert_friendly_interface_to_friendly_descr($interface) {
5676

    
5677
	$iface = config_get_path("interfaces/{$interface}");
5678
	switch ($interface) {
5679
		case "l2tp":
5680
			$ifdesc = "L2TP";
5681
			break;
5682
		case "pptp":
5683
			$ifdesc = "PPTP";
5684
			break;
5685
		case "pppoe":
5686
			$ifdesc = "PPPoE";
5687
			break;
5688
		case "openvpn":
5689
			$ifdesc = "OpenVPN";
5690
			break;
5691
		case "lo0":
5692
			$ifdesc = "Loopback";
5693
			break;
5694
		case "enc0":
5695
		case "ipsec":
5696
		case "IPsec":
5697
			$ifdesc = "IPsec";
5698
			break;
5699
		default:
5700
			if ($iface) {
5701
				if (empty($iface['descr'])) {
5702
					$ifdesc = strtoupper($interface);
5703
				} else {
5704
					$ifdesc = strtoupper($iface['descr']);
5705
				}
5706
				break;
5707
			} elseif (substr($interface, 0, 4) == '_vip') {
5708
				foreach (config_get_path('virtualip/vip', []) as $vip) {
5709
					if (($vip['mode'] == "carp") || ($vip['mode'] == "ipalias")) {
5710
						if ($interface == "_vip{$vip['uniqid']}") {
5711
							$descr = $vip['subnet'];
5712
							if (!empty($vip['vhid'])) {
5713
								$descr .= " (vhid {$vip['vhid']})";
5714
							}
5715
							if (!empty($vip['descr'])) {
5716
								$descr .= " - " .$vip['descr'];
5717
							}
5718
							return $descr;
5719
						}
5720
					}
5721
				}
5722
			} elseif (substr($interface, 0, 5) == '_lloc') {
5723
				return get_interface_linklocal($interface);
5724
			} else {
5725
				foreach (config_get_path('ifgroups/ifgroupentry', []) as $ifgen) {
5726
					if ($ifgen['ifname'] === $interface) {
5727
						return $ifgen['ifname'];
5728
					}
5729
				}
5730

    
5731
				/* if list */
5732
				$ifdescrs = get_configured_interface_with_descr(true);
5733
				foreach ($ifdescrs as $if => $ifname) {
5734
					if ($if == $interface || $ifname == $interface) {
5735
						return $ifname;
5736
					}
5737
				}
5738
			}
5739
			break;
5740
	}
5741

    
5742
	return $ifdesc;
5743
}
5744

    
5745
function convert_real_interface_to_friendly_descr($interface) {
5746

    
5747
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5748

    
5749
	if (!empty($ifdesc)) {
5750
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5751
	}
5752

    
5753
	return $interface;
5754
}
5755

    
5756
/*
5757
 *  get_parent_interface($interface):
5758
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5759
 *				or virtual interface (i.e. vlan)
5760
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5761
 *			-- returns $interface passed in if $interface parent is not found
5762
 *			-- returns empty array if an invalid interface is passed
5763
 *	(Only handles ppps and vlans now.)
5764
 */
5765
function get_parent_interface($interface, $avoidrecurse = false) {
5766
	$parents = array();
5767
	//Check that we got a valid interface passed
5768
	$realif = get_real_interface($interface);
5769
	if ($realif == NULL) {
5770
		return $parents;
5771
	}
5772

    
5773
	// If we got a real interface, find it's friendly assigned name
5774
	if ($interface == $realif && $avoidrecurse == false) {
5775
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5776
	}
5777

    
5778
	$iface = config_get_path("interfaces/{$interface}");
5779
	if (!empty($interface) && $iface) {
5780
		$ifcfg = $iface;
5781
		switch ($ifcfg['ipaddr']) {
5782
			case "ppp":
5783
			case "pppoe":
5784
			case "pptp":
5785
			case "l2tp":
5786
				if (empty($parents)) {
5787
					foreach (config_get_path('ppps/ppp') as $ppp) {
5788
						if ($ifcfg['if'] == $ppp['if']) {
5789
							$ports = explode(',', $ppp['ports']);
5790
							foreach ($ports as $pid => $parent_if) {
5791
								$parents[$pid] = get_real_interface($parent_if);
5792
							}
5793
							break;
5794
						}
5795
					}
5796
				}
5797
				break;
5798
			case "dhcp":
5799
			case "static":
5800
			default:
5801
				// Handle _vlans
5802
				$vlan = interface_is_vlan($ifcfg['if']);
5803
				if ($vlan != NULL) {
5804
					$parents[0] = $vlan['if'];
5805
				}
5806
				break;
5807
		}
5808
	}
5809

    
5810
	if (empty($parents)) {
5811
		// Handle _vlans not assigned to an interface
5812
		$vlan = interface_is_vlan($realif);
5813
		if ($vlan != NULL) {
5814
			$parents[0] = $vlan['if'];
5815
		}
5816
	}
5817

    
5818
	if (empty($parents)) {
5819
		/* Handle LAGGs. */
5820
		$lagg = interface_is_type($realif, 'lagg');
5821
		if ($lagg != NULL && isset($lagg['members'])) {
5822
			$parents = explode(",", $lagg['members']);
5823
		}
5824
	}
5825

    
5826
	if (empty($parents)) {
5827
		$parents[0] = $realif;
5828
	}
5829

    
5830
	return $parents;
5831
}
5832

    
5833
/*
5834
 *  get_parent_physical_interface($interface):
5835
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5836
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5837
 */
5838
function get_parent_physical_interface($interface) {
5839

    
5840
	$realif = get_parent_interface($interface);
5841

    
5842
	if (substr($realif[0], 0, 4) == "lagg") {
5843
		foreach (config_get_path('laggs/lagg', []) as $lagg) {
5844
			if ($realif[0] == $lagg['laggif']) {
5845
				return explode(",", $lagg['members']);
5846
			}
5847
		}
5848
	} else {
5849
		return $realif;
5850
	}
5851
}
5852

    
5853
function interface_is_wireless_clone($wlif) {
5854
	if (!stristr($wlif, "_wlan")) {
5855
		return false;
5856
	} else {
5857
		return true;
5858
	}
5859
}
5860

    
5861
function interface_get_wireless_base($wlif) {
5862
	if (!stristr($wlif, "_wlan")) {
5863
		return $wlif;
5864
	} else {
5865
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5866
	}
5867
}
5868

    
5869
function interface_get_wireless_clone($wlif) {
5870
	if (!stristr($wlif, "_wlan")) {
5871
		return $wlif . "_wlan0";
5872
	} else {
5873
		return $wlif;
5874
	}
5875
}
5876

    
5877
function interface_list_wireless() {
5878
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5879

    
5880
	$result = array();
5881
	foreach ($portlist as $port) {
5882
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5883
			continue;
5884
		}
5885

    
5886
		$desc = $port . " ( " . get_single_sysctl(
5887
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5888

    
5889
		$result[] = array(
5890
		    "if" => $port,
5891
		    "descr" => $desc
5892
		);
5893
	}
5894

    
5895
	return $result;
5896
}
5897

    
5898
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = false) {
5899
	global $g;
5900

    
5901
	$wanif = NULL;
5902

    
5903
	switch ($interface) {
5904
		case "l2tp":
5905
			$wanif = "l2tp";
5906
			break;
5907
		case "pptp":
5908
			$wanif = "pptp";
5909
			break;
5910
		case "pppoe":
5911
			$wanif = "pppoe";
5912
			break;
5913
		case "openvpn":
5914
			$wanif = "openvpn";
5915
			break;
5916
		case "IPsec":
5917
		case "ipsec":
5918
		case "enc0":
5919
			$wanif = "enc0";
5920
			break;
5921
		case "ppp":
5922
			$wanif = "ppp";
5923
			break;
5924
		default:
5925
			if (substr($interface, 0, 4) == '_vip') {
5926
				$wanif = get_configured_vip_interface($interface);
5927
				if (!empty($wanif)) {
5928
					$wanif = get_real_interface($wanif);
5929
				}
5930
				break;
5931
			} elseif (substr($interface, 0, 5) == '_lloc') {
5932
				$interface = substr($interface, 5);
5933
			} elseif (interface_is_vlan($interface) != NULL ||
5934
			    does_interface_exist($interface, $flush)) {
5935
				/*
5936
				 * If a real interface was already passed simply
5937
				 * pass the real interface back.  This encourages
5938
				 * the usage of this function in more cases so that
5939
				 * we can combine logic for more flexibility.
5940
				 */
5941
				$wanif = $interface;
5942
				break;
5943
			}
5944

    
5945
			$cfg = config_get_path("interfaces/{$interface}");
5946
			if (empty($cfg))
5947
				break;
5948

    
5949
			if ($family == "inet6") {
5950
				switch ($cfg['ipaddrv6']) {
5951
					case "6rd":
5952
					case "6to4":
5953
						$wanif = "{$interface}_stf";
5954
						break;
5955
					case 'pppoe':
5956
					case 'ppp':
5957
					case 'l2tp':
5958
					case 'pptp':
5959
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5960
							$wanif = interface_get_wireless_clone($cfg['if']);
5961
						} else {
5962
							$wanif = $cfg['if'];
5963
						}
5964
						break;
5965
					default:
5966
						switch ($cfg['ipaddr']) {
5967
							case 'pppoe':
5968
							case 'ppp':
5969
							case 'l2tp':
5970
							case 'pptp':
5971
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
5972
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) ||
5973
								    isset($cfg['ipv6usev4iface']) || isset($cfg['slaacusev4iface'])) {
5974
									$wanif = $cfg['if'];
5975
								} else {
5976
									$parents = get_parent_interface($interface);
5977
									if (!empty($parents[0])) {
5978
										$wanif = $parents[0];
5979
									} else {
5980
										$wanif = $cfg['if'];
5981
									}
5982
								}
5983
								break;
5984
							default:
5985
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5986
									$wanif = interface_get_wireless_clone($cfg['if']);
5987
								} else {
5988
									$wanif = $cfg['if'];
5989
								}
5990
								break;
5991
						}
5992
						break;
5993
				}
5994
			} else {
5995
				// Wireless cloned NIC support (FreeBSD 8+)
5996
				// interface name format: $parentnic_wlanparentnic#
5997
				// example: ath0_wlan0
5998
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
5999
					$wanif = interface_get_wireless_clone($cfg['if']);
6000
				} else {
6001
					$wanif = $cfg['if'];
6002
				}
6003
			}
6004
			break;
6005
	}
6006

    
6007
	return $wanif;
6008
}
6009

    
6010
/* Guess the physical interface by providing a IP address */
6011
function guess_interface_from_ip($ipaddress) {
6012

    
6013
	if (!is_ipaddr($ipaddress)) {
6014
		return false;
6015
	}
6016

    
6017
	$route = route_get($ipaddress, '', true);
6018
	if (empty($route)) {
6019
		return false;
6020
	}
6021

    
6022
	if (!empty($route[0]['interface-name'])) {
6023
		return $route[0]['interface-name'];
6024
	}
6025

    
6026
	return false;
6027
}
6028

    
6029
/*
6030
 * find_ip_interface($ip): return the interface where an ip is defined
6031
 *   (or if $bits is specified, where an IP within the subnet is defined)
6032
 */
6033
function find_ip_interface($ip, $bits = null) {
6034
	if (!is_ipaddr($ip)) {
6035
		return false;
6036
	}
6037

    
6038
	$isv6ip = is_ipaddrv6($ip);
6039

    
6040
	/* if list */
6041
	$ifdescrs = get_configured_interface_list();
6042

    
6043
	foreach ($ifdescrs as $ifname) {
6044
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
6045
		if (is_null($ifip)) {
6046
			continue;
6047
		}
6048
		if (is_null($bits)) {
6049
			if ($ip == $ifip) {
6050
				$int = get_real_interface($ifname);
6051
				return $int;
6052
			}
6053
		} else {
6054
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
6055
				$int = get_real_interface($ifname);
6056
				return $int;
6057
			}
6058
		}
6059
	}
6060

    
6061
	return false;
6062
}
6063

    
6064
/*
6065
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
6066
 *   (or if $bits is specified, where an IP within the subnet is found)
6067
 */
6068
function find_virtual_ip_alias($ip, $bits = null) {
6069

    
6070
	if (!is_ipaddr($ip)) {
6071
		return false;
6072
	}
6073

    
6074
	$isv6ip = is_ipaddrv6($ip);
6075

    
6076
	foreach (config_get_path('virtualip/vip', []) as $vip) {
6077
		if ($vip['mode'] === "ipalias") {
6078
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
6079
				continue;
6080
			}
6081
			if (is_null($bits)) {
6082
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
6083
					return $vip;
6084
				}
6085
			} else {
6086
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
6087
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
6088
					return $vip;
6089
				}
6090
			}
6091
		}
6092
	}
6093
	return false;
6094
}
6095

    
6096
function link_interface_to_track6($int, $action = "") {
6097
	$list = array();
6098
	if (empty($int)) {
6099
		return $list;
6100
	}
6101

    
6102
	foreach (config_get_path('interfaces', []) as $ifname => $ifcfg) {
6103
		if (!isset($ifcfg['enable'])) {
6104
			continue;
6105
		}
6106
		if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
6107
			if ($action == "update") {
6108
				interface_track6_configure($ifname, $ifcfg);
6109
			} elseif ($action == "") {
6110
				$list[$ifname] = $ifcfg;
6111
			}
6112
		}
6113
	}
6114
	return $list;
6115
}
6116

    
6117
function interface_find_child_cfgmtu($realiface) {
6118
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
6119
	$vlans = link_interface_to_vlans($realiface);
6120
	$qinqs = link_interface_to_qinqs($realiface);
6121
	$bridge = link_interface_to_bridge($realiface);
6122
	$gifs = link_interface_to_tunnelif($interface, 'gif');
6123
	$gres = link_interface_to_tunnelif($interface, 'gre');
6124

    
6125
	$mtu = 0;
6126
	if (is_array($vlans)) {
6127
		foreach ($vlans as $vlan) {
6128
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
6129
			if (empty($ifass)) {
6130
				continue;
6131
			}
6132
			$vlanmtu = config_get_path("interfaces/{$ifass}/mtu");
6133
			if ($vlanmtu && (intval($vlanmtu) > $mtu)) {
6134
				$mtu = $vlanmtu;
6135
			}
6136
		}
6137
	}
6138
	if (is_array($qinqs)) {
6139
		foreach ($qinqs as $qinq) {
6140
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
6141
			if (empty($ifass)) {
6142
				continue;
6143
			}
6144

    
6145
			$qinqmtu = config_get_path("interfaces/{$ifass}/mtu");
6146
			if ($qinqmtu && (intval($qinqmtu) > $mtu)) {
6147
				$mtu = $qinqmtu;
6148
			}
6149
		}
6150
	}
6151
	foreach ($gifs as $gif) {
6152
		$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
6153
		if (empty($ifass)) {
6154
			continue;
6155
		}
6156

    
6157
		$gifmtu = config_get_path("interfaces/{$ifass}/mtu");
6158
		if ($gifmtu && (intval($gifmtu) > $mtu)) {
6159
			$mtu = $gifmtu;
6160
		}
6161
	}
6162
	foreach ($gres as $gre) {
6163
		$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
6164
		if (empty($ifass)) {
6165
			continue;
6166
		}
6167
		$gremtu = config_get_path("interfaces/{$ifass}/mtu");
6168
		if ($gremtu && (intval($gremtu) > $mtu)) {
6169
			$mtu = $gremtu;
6170
		}
6171
	}
6172
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
6173
	$ifassmtu = config_get_path("interfaces/{$ifass}/mtu");
6174
	if (!empty($ifass) && !empty($ifassmtu)) {
6175
		if ($ifassmtu > $mtu) {
6176
			$mtu = $ifassmtu;
6177
		}
6178
	}
6179
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
6180

    
6181
	return $mtu;
6182
}
6183

    
6184
function link_interface_to_vlans($int, $action = "") {
6185
	if (empty($int)) {
6186
		return;
6187
	}
6188

    
6189
	$ifaces = array();
6190
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
6191
		if ($int == $vlan['if']) {
6192
			if ($action == "update") {
6193
				interfaces_bring_up($int);
6194
			} else {
6195
				$ifaces[$vlan['tag']] = $vlan;
6196
			}
6197
		}
6198
	}
6199
	if (!empty($ifaces)) {
6200
		return $ifaces;
6201
	}
6202
}
6203

    
6204
function link_interface_to_qinqs($int, $action = "") {
6205
	if (empty($int)) {
6206
		return;
6207
	}
6208

    
6209
	$ifaces = array();
6210
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
6211
		if ($int == $qinq['if']) {
6212
			if ($action == "update") {
6213
				interfaces_bring_up($int);
6214
			} else {
6215
				$ifaces[$qinq['tag']] = $qinq;
6216
			}
6217
		}
6218
	}
6219
	if (!empty($ifaces)) {
6220
		return $ifaces;
6221
	}
6222
}
6223

    
6224
function link_interface_to_vips($int, $action = "", $vhid = '') {
6225
	$updatevips = false;
6226

    
6227
	$result = array();
6228
	foreach (config_get_path('virtualip/vip', []) as $vip) {
6229
		if (substr($vip['interface'], 0, 4) == "_vip") {
6230
			$iface = get_configured_vip_interface($vip['interface']);
6231
		} else {
6232
			$iface = $vip['interface'];
6233
		}
6234
		if ($int != $iface) {
6235
			continue;
6236
		}
6237
		if ($action == "update") {
6238
			$updatevips = true;
6239
		} else {
6240
			if (empty($vhid) || ($vhid == $vip['vhid']) ||
6241
				substr($vip['interface'], 0, 4) == "_vip") {
6242
				$result[] = $vip;
6243
			}
6244
		}
6245
	}
6246
	if ($updatevips === true) {
6247
		interfaces_vips_configure($int);
6248
	}
6249
	return $result;
6250

    
6251
	return NULL;
6252
}
6253

    
6254
/****f* interfaces/link_interface_to_bridge
6255
 * NAME
6256
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6257
 * INPUTS
6258
 *   $ip
6259
 * RESULT
6260
 *   bridge[0-99]
6261
 ******/
6262
function link_interface_to_bridge($int) {
6263
	foreach (config_get_path('bridges/bridged', []) as $bridge) {
6264
		if (in_array($int, explode(',', $bridge['members']))) {
6265
			return "{$bridge['bridgeif']}";
6266
		}
6267
	}
6268
}
6269

    
6270
function link_interface_to_lagg($int) {
6271
	foreach (config_get_path('laggs/lagg', []) as $lagg) {
6272
		if (in_array($int, explode(',', $lagg['members']))) {
6273
			return "{$lagg['laggif']}";
6274
		}
6275
	}
6276
}
6277

    
6278
function link_interface_to_group($int) {
6279
	$result = array();
6280

    
6281
	foreach (config_get_path('ifgroups/ifgroupentry') as $group) {
6282
		if (in_array($int, explode(" ", $group['members']))) {
6283
			$result[$group['ifname']] = $int;
6284
		}
6285
	}
6286

    
6287
	return $result;
6288
}
6289

    
6290
function link_interface_to_tunnelif($interface, $type, $remote = 'any') {
6291
	$result = array();
6292

    
6293
	if (empty($interface)) {
6294
		return $result;
6295
	}
6296

    
6297
	if (!in_array($type, array('gre', 'gif'))) {
6298
		return $result;
6299
	}
6300

    
6301
	foreach (config_get_path("{$type}s/{$type}", []) as $tunnel) {
6302
		if (($tunnel['if'] == $interface) &&
6303
			(($remote == 'any') ||
6304
			 (is_ipaddrv4($tunnel['remote-addr']) && ($remote == 'inet')) ||
6305
			 (is_ipaddrv6($tunnel['remote-addr']) && ($remote == 'inet6')))) { 
6306
			$result[] = $tunnel;
6307
		}
6308
	}
6309

    
6310
	return $result;
6311
}
6312

    
6313
function link_interface_to_ppp_tunnelif($interface) {
6314
	$result = array();
6315

    
6316
	if (empty($interface)) {
6317
		return $result;
6318
	}
6319

    
6320
	init_config_arr(array('ppps', 'ppp'));
6321
	$realif = get_real_interface($interface);
6322
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
6323
		if (($ppp['ports'] == $realif) && in_array($ppp['type'], array('l2tp', 'pptp'))) { 
6324
			$result[] = $ppp;
6325
		}
6326
	}
6327

    
6328
	return $result;
6329
}
6330

    
6331
/*
6332
 * find_interface_ip($interface): return the interface ip (first found)
6333
 */
6334
function find_interface_ip($interface, $flush = false) {
6335
	global $interface_ip_arr_cache;
6336
	global $interface_sn_arr_cache;
6337

    
6338
	$interface = str_replace("\n", "", $interface);
6339

    
6340
	if (!does_interface_exist($interface)) {
6341
		return;
6342
	}
6343

    
6344
	/* Setup IP cache */
6345
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6346
		if (file_exists("/var/db/${interface}_ip")) {
6347
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6348
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6349
			foreach ($ifaddrs as $ifaddr) {
6350
				list($ip, $mask) = explode("/", $ifaddr);
6351
				if ($ip == $ifip) {
6352
					$interface_ip_arr_cache[$interface] = $ip;
6353
					$interface_sn_arr_cache[$interface] = $mask;
6354
					break;
6355
				}
6356
			}
6357
		}
6358
		if (!isset($interface_ip_arr_cache[$interface])) {
6359
			$ifinfo = get_interface_addresses($interface);
6360
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6361
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6362
		}
6363
	}
6364

    
6365
	return $interface_ip_arr_cache[$interface];
6366
}
6367

    
6368
/*
6369
 * find_interface_ipv6($interface): return the interface ip (first found)
6370
 */
6371
function find_interface_ipv6($interface, $flush = false) {
6372
	global $interface_ipv6_arr_cache;
6373
	global $interface_snv6_arr_cache;
6374

    
6375
	$interface = trim($interface);
6376
	$interface = get_real_interface($interface);
6377

    
6378
	if (!does_interface_exist($interface)) {
6379
		return;
6380
	}
6381

    
6382
	/* Setup IP cache */
6383
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6384
		$ifinfo = get_interface_addresses($interface);
6385
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6386
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6387
	}
6388

    
6389
	return $interface_ipv6_arr_cache[$interface];
6390
}
6391

    
6392
/*
6393
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6394
 */
6395
function find_interface_ipv6_ll($interface, $flush = false) {
6396
	global $interface_llv6_arr_cache;
6397

    
6398
	$interface = str_replace("\n", "", $interface);
6399

    
6400
	if (!does_interface_exist($interface)) {
6401
		return;
6402
	}
6403

    
6404
	/* Setup IP cache */
6405
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6406
		$ifinfo = pfSense_getall_interface_addresses($interface);
6407
		foreach ($ifinfo as $line) {
6408
			if (strstr($line, ":")) {
6409
				$parts = explode("/", $line);
6410
				if (is_linklocal($parts[0])) {
6411
					$ifinfo['linklocal'] = $parts[0];
6412
				}
6413
			}
6414
		}
6415
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6416
	}
6417
	return $interface_llv6_arr_cache[$interface];
6418
}
6419

    
6420
function find_interface_subnet($interface, $flush = false) {
6421
	global $interface_sn_arr_cache;
6422
	global $interface_ip_arr_cache;
6423

    
6424
	$interface = str_replace("\n", "", $interface);
6425
	if (does_interface_exist($interface) == false) {
6426
		return;
6427
	}
6428

    
6429
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6430
		$ifinfo = get_interface_addresses($interface);
6431
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6432
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6433
	}
6434

    
6435
	return $interface_sn_arr_cache[$interface];
6436
}
6437

    
6438
function find_interface_subnetv6($interface, $flush = false) {
6439
	global $interface_snv6_arr_cache;
6440
	global $interface_ipv6_arr_cache;
6441

    
6442
	$interface = str_replace("\n", "", $interface);
6443
	if (does_interface_exist($interface) == false) {
6444
		return;
6445
	}
6446

    
6447
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6448
		$ifinfo = get_interface_addresses($interface);
6449
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6450
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6451
	}
6452

    
6453
	return $interface_snv6_arr_cache[$interface];
6454
}
6455

    
6456
function ip_in_interface_alias_subnet($interface, $ipalias) {
6457
	if (empty($interface) || !is_ipaddr($ipalias)) {
6458
		return false;
6459
	}
6460
	foreach (config_get_path('virtualip/vip',[]) as $vip) {
6461
		switch ($vip['mode']) {
6462
		case "ipalias":
6463
			if ($vip['interface'] <> $interface) {
6464
				break;
6465
			}
6466
			$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6467
			if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6468
				return true;
6469
			}
6470
			break;
6471
		}
6472
	}
6473

    
6474
	return false;
6475
}
6476

    
6477
function get_possible_listen_ips($include_ipv6_link_local=false) {
6478

    
6479
	$interfaces = get_configured_interface_with_descr();
6480
	foreach ($interfaces as $iface => $ifacename) {
6481
		if ($include_ipv6_link_local) {
6482
			/* This is to avoid going though added ll below */
6483
			if (substr($iface, 0, 5) == '_lloc') {
6484
				continue;
6485
			}
6486
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6487
			if (!empty($llip)) {
6488
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6489
			}
6490
		}
6491
	}
6492
	$viplist = get_configured_vip_list();
6493
	foreach ($viplist as $vip => $address) {
6494
		$interfaces[$vip] = $address;
6495
		if (get_vip_descr($address)) {
6496
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6497
		}
6498
	}
6499

    
6500
	$interfaces['lo0'] = 'Localhost';
6501

    
6502
	return $interfaces;
6503
}
6504

    
6505
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6506
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6507
	foreach (array('server', 'client') as $mode) {
6508
		foreach (config_get_path("openvpn/openvpn-{$mode}", []) as $setting) {
6509
			if (!isset($setting['disable'])) {
6510
				$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6511
				$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6512
			}
6513
		}
6514
	}
6515

    
6516
	init_config_arr(array('ipsec', 'phase1'));
6517
	foreach (config_get_path('ipsec/phase1') as $p1) {
6518
		if ($p1['disabled']) {
6519
			continue;
6520
		}
6521
		if (ipsec_vti($p1)) {
6522
			$vtiiflist = interface_ipsec_vti_list_p1($p1);
6523
			if (!empty($vtiiflist)) {
6524
				$sourceips = array_merge($sourceips, $vtiiflist);
6525
			}
6526
		}
6527
	}
6528
	return $sourceips;
6529
}
6530

    
6531
function get_interface_ip($interface = "wan", $gateways_status = false) {
6532
	if (substr($interface, 0, 4) == '_vip') {
6533
		return get_configured_vip_ipv4($interface);
6534
	} elseif (substr($interface, 0, 5) == '_lloc') {
6535
		/* No link-local address for v4. */
6536
		return null;
6537
	}
6538

    
6539
	$realif = get_failover_interface($interface, 'inet', $gateways_status);
6540
	if (!$realif) {
6541
		return null;
6542
	}
6543

    
6544
	if (substr($realif, 0, 4) == '_vip') {
6545
		return get_configured_vip_ipv4($realif);
6546
	} elseif (substr($realif, 0, 5) == '_lloc') {
6547
		/* No link-local address for v4. */
6548
		return null;
6549
	}
6550

    
6551
	$iface = config_get_path("interfaces/{$interface}");
6552
	if (is_array($iface) && is_ipaddr($iface['ipaddr'])) {
6553
		return ($iface['ipaddr']);
6554
	}
6555

    
6556
	/*
6557
	 * Beaware that find_interface_ip() is our last option, it will
6558
	 * return the first IP it find on interface, not necessarily the
6559
	 * main IP address.
6560
	 */
6561
	$curip = find_interface_ip($realif);
6562
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6563
		return $curip;
6564
	} else {
6565
		return null;
6566
	}
6567
}
6568

    
6569
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false, $gateways_status = false) {
6570
	if (substr($interface, 0, 4) == '_vip') {
6571
		return get_configured_vip_ipv6($interface);
6572
	} elseif (substr($interface, 0, 5) == '_lloc') {
6573
		return get_interface_linklocal($interface);
6574
	}
6575

    
6576
	$realif = get_failover_interface($interface, 'inet6', $gateways_status);
6577
	if (!$realif) {
6578
		return null;
6579
	}
6580

    
6581
	if (substr($realif, 0, 4) == '_vip') {
6582
		return get_configured_vip_ipv6($realif);
6583
	} elseif (substr($realif, 0, 5) == '_lloc') {
6584
		return get_interface_linklocal($realif);
6585
	}
6586

    
6587
	$iface = config_get_path("interfaces/{$interface}");
6588
	if (is_array($iface)) {
6589
		switch ($iface['ipaddr']) {
6590
			case 'pppoe':
6591
			case 'l2tp':
6592
			case 'pptp':
6593
			case 'ppp':
6594
				if (($iface['ipaddrv6'] == 'dhcp6') ||
6595
				    ($iface['ipaddrv6'] == 'slaac')) {
6596
					$realif = get_real_interface($interface, 'inet6', false);
6597
				}
6598
				break;
6599
		}
6600
		if (is_ipaddrv6($iface['ipaddrv6'])) {
6601
			return ($iface['ipaddrv6']);
6602
		}
6603
	}
6604

    
6605
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6606
	$checkif = is_array($iface) ? $interface : convert_real_interface_to_friendly_interface_name($interface);
6607
	if (config_get_path("interfaces/{$checkif}/ipaddrv6", "") == 'track6') { 
6608
		$curip = get_interface_track6ip($checkif);
6609
		if ($curip) {
6610
			return $curip[0];
6611
		}
6612
	}
6613

    
6614
	/*
6615
	 * Beaware that find_interface_ip() is our last option, it will
6616
	 * return the first IP it find on interface, not necessarily the
6617
	 * main IP address.
6618
	 */
6619
	$curip = find_interface_ipv6($realif, $flush);
6620
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6621
		return $curip;
6622
	} else {
6623
		/*
6624
		 * NOTE: On the case when only the prefix is requested,
6625
		 * the communication on WAN will be done over link-local.
6626
		 */
6627
		$iface = config_get_path("interfaces/{$interface}");
6628
		if ($linklocal_fallback || (is_array($iface) && isset($iface['dhcp6prefixonly']))) {
6629
			$curip = find_interface_ipv6_ll($realif, $flush);
6630
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6631
				return $curip;
6632
			}
6633
		}
6634
	}
6635
	return null;
6636
}
6637

    
6638
function get_interface_linklocal($interface = "wan") {
6639

    
6640
	$realif = get_failover_interface($interface, 'inet6');
6641
	if (!$realif) {
6642
		return null;
6643
	}
6644

    
6645
	if (substr($interface, 0, 4) == '_vip') {
6646
		$realif = get_real_interface($interface);
6647
	} elseif (substr($interface, 0, 5) == '_lloc') {
6648
		$realif = get_real_interface(substr($interface, 5));
6649
	}
6650

    
6651
	$curip = find_interface_ipv6_ll($realif);
6652
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6653
		return $curip;
6654
	} else {
6655
		return null;
6656
	}
6657
}
6658

    
6659
function get_interface_track6ip($interface = "wan") {
6660
	$realif = get_real_interface($interface);
6661
	$vips = get_configured_vip_list('inet6');
6662

    
6663
	foreach (pfSense_getall_interface_addresses($realif) as $ifaddr) {
6664
		list($ip, $bits) = explode("/", $ifaddr);
6665
		$ip = text_to_compressed_ip6($ip);
6666
		if (is_ipaddrv6($ip) && !is_linklocal($ip)) {
6667
			if (is_array($vips) && !empty($vips)) {
6668
				foreach ($vips as $vip) {
6669
					if ($ip == text_to_compressed_ip6($vip)) {
6670
						continue 2;
6671
					}
6672
				}
6673
			}
6674
			return array($ip, $bits);
6675
		}
6676
	}
6677
	return false;
6678
}
6679

    
6680
function get_interface_subnet($interface = "wan") {
6681
	if (substr($interface, 0, 4) == '_vip') {
6682
		return (get_configured_vip_subnetv4($interface));
6683
	}
6684

    
6685
	$iface = config_get_path("interfaces/{$interface}");
6686
	if (is_array($iface) && !empty($iface['subnet']) && is_ipaddrv4($iface['ipaddr'])) {
6687
		return ($iface['subnet']);
6688
	}
6689

    
6690
	$realif = get_real_interface($interface);
6691
	if (!$realif) {
6692
		return (NULL);
6693
	}
6694

    
6695
	$cursn = find_interface_subnet($realif);
6696
	if (!empty($cursn)) {
6697
		return ($cursn);
6698
	}
6699

    
6700
	return (NULL);
6701
}
6702

    
6703
function get_interface_subnetv6($interface = "wan") {
6704
	if (substr($interface, 0, 4) == '_vip') {
6705
		return (get_configured_vip_subnetv6($interface));
6706
	} elseif (substr($interface, 0, 5) == '_lloc') {
6707
		$interface = substr($interface, 5);
6708
	}
6709

    
6710
	$iface = config_get_path("interfaces/{$interface}");
6711
	if (is_array($iface) && !empty($iface['subnetv6']) && is_ipaddrv6($iface['ipaddrv6'])) {
6712
		return ($iface['subnetv6']);
6713
	}
6714

    
6715
	$realif = get_real_interface($interface, 'inet6');
6716
	if (!$realif) {
6717
		return (NULL);
6718
	}
6719

    
6720
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6721
	if (config_get_path("interfaces/{$interface}/ipaddrv6") == 'track6') {
6722
		$curip = get_interface_track6ip($interface);
6723
		if ($curip) {
6724
			return $curip[1];
6725
		}
6726
	}
6727

    
6728
	$cursn = find_interface_subnetv6($realif);
6729
	if (!empty($cursn)) {
6730
		return ($cursn);
6731
	}
6732

    
6733
	return (NULL);
6734
}
6735

    
6736
/* return outside interfaces with a gateway */
6737
function get_interfaces_with_gateway() {
6738

    
6739
	$ints = array();
6740

    
6741
	/* loop interfaces, check config for outbound */
6742
	foreach (config_get_path('interfaces', []) as $ifdescr => $ifname) {
6743
		switch ($ifname['ipaddr']) {
6744
			case "dhcp":
6745
			case "pppoe":
6746
			case "pptp":
6747
			case "l2tp":
6748
			case "ppp":
6749
				$ints[$ifdescr] = $ifdescr;
6750
				break;
6751
			default:
6752
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6753
				    !empty($ifname['gateway'])) {
6754
					$ints[$ifdescr] = $ifdescr;
6755
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6756
				    !empty($ifname['gateway'])) {
6757
					$ints[$ifdescr] = $ifdescr;
6758
				}
6759

    
6760
				break;
6761
		}
6762
	}
6763
	return $ints;
6764
}
6765

    
6766
/* return true if interface has a gateway */
6767
function interface_has_gateway($friendly) {
6768
	$ifname = config_get_path("interfaces/{$friendly}");
6769
	if (!empty($ifname)) {
6770
		switch ($ifname['ipaddr']) {
6771
			case "dhcp":
6772
				/* see https://redmine.pfsense.org/issues/5135 */
6773
				if (get_interface_gateway($friendly)) {
6774
					return true;
6775
				}
6776
				break;
6777
			case "pppoe":
6778
			case "pptp":
6779
			case "l2tp":
6780
			case "ppp":
6781
				return true;
6782
				break;
6783
			default:
6784
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6785
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6786
					return true;
6787
				}
6788
				$tunnelif = substr($ifname['if'], 0, 3);
6789
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6790
					if (find_interface_ip($ifname['if'])) {
6791
						return true;
6792
					}
6793
				}
6794
				if (!empty($ifname['gateway'])) {
6795
					return true;
6796
				}
6797
				break;
6798
		}
6799
	}
6800

    
6801
	return false;
6802
}
6803

    
6804
/* return true if interface has a gateway */
6805
function interface_has_gatewayv6($friendly) {
6806
	$ifname = config_get_path("interfaces/{$friendly}");
6807
	if (!empty($ifname)) {
6808
		switch ($ifname['ipaddrv6']) {
6809
			case "slaac":
6810
			case "dhcp6":
6811
			case "6to4":
6812
			case "6rd":
6813
				return true;
6814
				break;
6815
			default:
6816
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6817
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6818
					return true;
6819
				}
6820
				$tunnelif = substr($ifname['if'], 0, 3);
6821
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6822
					if (find_interface_ipv6($ifname['if'])) {
6823
						return true;
6824
					}
6825
				}
6826
				if (!empty($ifname['gatewayv6'])) {
6827
					return true;
6828
				}
6829
				break;
6830
		}
6831
	}
6832

    
6833
	return false;
6834
}
6835

    
6836
/****f* interfaces/is_altq_capable
6837
 * NAME
6838
 *   is_altq_capable - Test if interface is capable of using ALTQ
6839
 * INPUTS
6840
 *   $int            - string containing interface name
6841
 * RESULT
6842
 *   boolean         - true or false
6843
 ******/
6844

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

    
6860
	$int_family = remove_ifindex($int);
6861

    
6862
	if (in_array($int_family, $capable)) {
6863
		return true;
6864
	} elseif (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6865
		return true;
6866
	} elseif (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6867
		return true;
6868
	} elseif (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6869
		return true;
6870
	} else {
6871
		return false;
6872
	}
6873
}
6874

    
6875
/****f* interfaces/is_interface_wireless
6876
 * NAME
6877
 *   is_interface_wireless - Returns if an interface is wireless
6878
 * RESULT
6879
 *   $tmp       - Returns if an interface is wireless
6880
 ******/
6881
function is_interface_wireless($interface) {
6882
	global $g;
6883

    
6884
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6885
	if (config_get_path("interfaces/{$friendly}/wireless") === null) {
6886
		if (preg_match($g['wireless_regex'], $interface)) {
6887
			init_config_arr(['interfaces', $friendly, 'wireless']);
6888
			return true;
6889
		}
6890
		return false;
6891
	} else {
6892
		return true;
6893
	}
6894
}
6895

    
6896
function get_wireless_modes($interface) {
6897
	/* return wireless modes and channels */
6898
	$wireless_modes = array();
6899

    
6900
	$cloned_interface = get_real_interface($interface);
6901

    
6902
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6903
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6904
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\n\" \$3 }'";
6905
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6906

    
6907
		$interface_channels = [];
6908
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6909
		$interface_channel_count = count($interface_channels);
6910

    
6911
		$c = 0;
6912
		while ($c < $interface_channel_count) {
6913
			$channel_line = explode(",", $interface_channels["$c"]);
6914
			$wireless_mode = trim($channel_line[0]);
6915
			$wireless_channel = trim($channel_line[1]);
6916
			if (trim($wireless_mode) != "") {
6917
				/* if we only have 11g also set 11b channels */
6918
				if ($wireless_mode == "11g") {
6919
					if (!isset($wireless_modes["11b"])) {
6920
						$wireless_modes["11b"] = array();
6921
					}
6922
				} elseif ($wireless_mode == "11g ht") {
6923
					if (!isset($wireless_modes["11b"])) {
6924
						$wireless_modes["11b"] = array();
6925
					}
6926
					if (!isset($wireless_modes["11g"])) {
6927
						$wireless_modes["11g"] = array();
6928
					}
6929
					$wireless_mode = "11ng";
6930
				} elseif ($wireless_mode == "11a ht") {
6931
					if (!isset($wireless_modes["11a"])) {
6932
						$wireless_modes["11a"] = array();
6933
					}
6934
					$wireless_mode = "11na";
6935
				}
6936
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
6937
			}
6938
			$c++;
6939
		}
6940
	}
6941
	return($wireless_modes);
6942
}
6943

    
6944
function get_wireless_channels($interface) {
6945
		$chan_list = "/sbin/ifconfig -v " . escapeshellarg($interface) . " list chan";
6946
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\n\" \$3 }'";
6947
		$format_list = "/usr/bin/awk '{print \$5 \",\" \$6 \",\" \$1}'";
6948

    
6949
		$interface_channels = [];
6950
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6951
		return $interface_channels;
6952
}
6953

    
6954
/* return wireless HT modes */
6955
function get_wireless_ht_modes($interface) {
6956
	$wireless_hts_supported = array(0 => gettext('Auto'));
6957

    
6958
	$cloned_interface = get_real_interface($interface);
6959

    
6960
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6961
		$interface_channels = get_wireless_channels($cloned_interface);
6962

    
6963
		foreach ($interface_channels as $channel) {
6964
			$channel_line = explode(",", $channel);
6965
			$wireless_ht = trim($channel_line[1]);
6966
			if (!empty($wireless_ht)) {
6967
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
6968
			}
6969
		}
6970
	}
6971
	return($wireless_hts_supported);
6972
}
6973

    
6974
/* return wireless HT by channel/standard */
6975
function get_wireless_ht_list($interface) {
6976
	$wireless_hts = array();
6977

    
6978
	$cloned_interface = get_real_interface($interface);
6979

    
6980
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6981
		$interface_channels = get_wireless_channels($cloned_interface);
6982
		$interface_channel_count = count($interface_channels);
6983

    
6984
		$c = 0;
6985
		while ($c < $interface_channel_count) {
6986
			$channel_line = explode(",", $interface_channels["$c"]);
6987
			$wireless_mode = trim($channel_line[0]);
6988
			$wireless_ht = trim($channel_line[1]);
6989
			$wireless_channel = trim($channel_line[2]);
6990
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
6991
				if ($wireless_mode == "11g") {
6992
					if (!isset($wireless_modes["11g"])) {
6993
						$wireless_hts["11g"] = array();
6994
					}
6995
					$wireless_mode = "11ng";
6996
				} elseif ($wireless_mode == "11a") {
6997
					if (!isset($wireless_modes["11a"])) {
6998
						$wireless_hts["11a"] = array();
6999
					}
7000
					$wireless_mode = "11na";
7001
				}
7002
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
7003
			}
7004
			$c++;
7005
		}
7006
	}
7007
	return($wireless_hts);
7008
}
7009

    
7010
/* return channel numbers, frequency, max txpower, and max regulation txpower */
7011
function get_wireless_channel_info($interface) {
7012
	$wireless_channels = array();
7013

    
7014
	$cloned_interface = get_real_interface($interface);
7015

    
7016
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7017
		$chan_list = "/sbin/ifconfig " . escapeshellarg($cloned_interface) . " list txpower";
7018
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\n\" \$3 }'";
7019
		$format_list = "/usr/bin/awk '{print \$1 \",\" \$3 \" \" \$4 \",\" \$5 \",\" \$7}'";
7020

    
7021
		$interface_channels = [];
7022
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7023

    
7024
		foreach ($interface_channels as $channel_line) {
7025
			$channel_line = explode(",", $channel_line);
7026
			if (!isset($wireless_channels[$channel_line[0]])) {
7027
				$wireless_channels[$channel_line[0]] = $channel_line;
7028
			}
7029
		}
7030
	}
7031
	return($wireless_channels);
7032
}
7033

    
7034
function set_interface_mtu($interface, $mtu) {
7035

    
7036
	/* LAGG interface must be destroyed and re-created to change MTU */
7037
	if ((substr($interface, 0, 4) == 'lagg') &&
7038
	    (!strstr($interface, "."))) {
7039
		foreach (config_get_path('laggs/lagg', []) as $lagg) {
7040
			if ($lagg['laggif'] == $interface) {
7041
				interface_lagg_configure($lagg);
7042
				break;
7043
			}
7044
		}
7045
	} else {
7046
		pfSense_interface_mtu($interface, $mtu);
7047
		set_ipv6routes_mtu($interface, $mtu);
7048
	}
7049
}
7050

    
7051
/****f* interfaces/get_interface_mtu
7052
 * NAME
7053
 *   get_interface_mtu - Return the mtu of an interface
7054
 * RESULT
7055
 *   $tmp       - Returns the mtu of an interface
7056
 ******/
7057
function get_interface_mtu($interface) {
7058
	$mtu = pfSense_interface_getmtu($interface);
7059
	return $mtu['mtu'];
7060
}
7061

    
7062
function get_interface_mac($interface) {
7063
	$macinfo = get_interface_addresses($interface);
7064
	return $macinfo["macaddr"];
7065
}
7066

    
7067
function get_interface_vendor_mac($interface) {
7068
	global $g;
7069

    
7070
	$macinfo = get_interface_addresses($interface);
7071
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7072
	    "00:00:00:00:00:00") {
7073
		return ($macinfo["hwaddr"]);
7074
	}
7075

    
7076
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7077
	if (file_exists($hwaddr_file)) {
7078
		$macaddr = trim(file_get_contents($hwaddr_file));
7079
		if (is_macaddr($macaddr)) {
7080
			return ($macaddr);
7081
		}
7082
	} elseif (is_macaddr($macinfo['macaddr'])) {
7083
		/* Save original macaddress to be restored when necessary */
7084
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7085
	}
7086

    
7087
	return (NULL);
7088
}
7089

    
7090
/****f* pfsense-utils/generate_random_mac_address
7091
 * NAME
7092
 *   generate_random_mac - generates a random mac address
7093
 * INPUTS
7094
 *   none
7095
 * RESULT
7096
 *   $mac - a random mac address
7097
 ******/
7098
function generate_random_mac_address() {
7099
	$mac = "02";
7100
	for ($x = 0; $x < 5; $x++) {
7101
		$mac .= ":" . dechex(rand(16, 255));
7102
	}
7103
	return $mac;
7104
}
7105

    
7106
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7107
	global $g;
7108

    
7109
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7110

    
7111
	if (!empty($iface) && !empty($pppif)) {
7112
		$cron_cmd = <<<EOD
7113
#!/bin/sh
7114
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7115
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7116

    
7117
EOD;
7118

    
7119
		@file_put_contents($cron_file, $cron_cmd);
7120
		chmod($cron_file, 0755);
7121
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7122
	} else {
7123
		unlink_if_exists($cron_file);
7124
	}
7125
}
7126

    
7127
function get_interface_default_mtu($type = "ethernet") {
7128
	switch ($type) {
7129
		case "gre":
7130
			return 1476;
7131
			break;
7132
		case "gif":
7133
			return 1280;
7134
			break;
7135
		case "tun":
7136
		case "vlan":
7137
		case "tap":
7138
		case "ethernet":
7139
		default:
7140
			return 1500;
7141
			break;
7142
	}
7143

    
7144
	/* Never reached */
7145
	return 1500;
7146
}
7147

    
7148
function get_vip_descr($ipaddress) {
7149

    
7150
	foreach (config_get_path('virtualip/vip', []) as $vip) {
7151
		if ($vip['subnet'] == $ipaddress) {
7152
			return ($vip['descr']);
7153
		}
7154
	}
7155
	return "";
7156
}
7157

    
7158
function interfaces_staticarp_configure($if) {
7159
	if (config_get_path('system/developerspew')) {
7160
		$mt = microtime();
7161
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7162
	}
7163

    
7164
	$ifcfg = config_get_path("interfaces/{$if}");
7165

    
7166
	if (!$ifcfg['if'] || !$ifcfg['enable']) {
7167
		return 0;
7168
	}
7169

    
7170
	/* Enable staticarp, if enabled */
7171
	$staticarp = config_get_path("dhcpd/{$if}/staticarp");
7172
	if ($staticarp) {
7173
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7174
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7175
	} else {
7176
		/*
7177
		 * Interfaces do not have staticarp enabled by default
7178
		 * Let's not disable staticarp on freshly created interfaces
7179
		 */
7180
		if (!platform_booting()) {
7181
			mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7182
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7183
		}
7184
	}
7185

    
7186
	/* Enable static arp entries */
7187
	$staticmap = config_get_path("dhcpd/{$if}/staticmap", []);
7188
	if (is_array($staticmap)) {
7189
		foreach ($staticmap as $arpent) {
7190
			if (empty($arpent['ipaddr']) || empty($arpent['mac'])) {
7191
				continue;
7192
			}
7193
			if ($staticarp || isset($arpent['arp_table_static_entry'])) {
7194
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7195
			}
7196
		}
7197
	}
7198

    
7199
	return 0;
7200
}
7201

    
7202
function get_failover_interface($interface, $family = "all", $gateways_status = false) {
7203
	/* shortcut to get_real_interface if we find it in the config */
7204
	if (is_array(config_get_path("interfaces/{$interface}"))) {
7205
		return get_real_interface($interface, $family);
7206
	}
7207

    
7208
	/* compare against gateway groups */
7209
	$a_groups = return_gateway_groups_array(true, $gateways_status);
7210
	if (is_array($a_groups[$interface])) {
7211
		/* we found a gateway group, fetch the interface or vip */
7212
		if (!empty($a_groups[$interface][0]['vip'])) {
7213
			return $a_groups[$interface][0]['vip'];
7214
		} else {
7215
			return $a_groups[$interface][0]['int'];
7216
		}
7217
	}
7218
	/* fall through to get_real_interface */
7219
	/* XXX: Really needed? */
7220
	return get_real_interface($interface, $family);
7221
}
7222

    
7223
/****f* interfaces/interface_has_dhcp
7224
 * NAME
7225
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7226
 * INPUTS
7227
 *   interface or gateway group name
7228
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7229
 * RESULT
7230
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7231
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7232
 ******/
7233
function interface_has_dhcp($interface, $family = 4) {
7234
	$iface = config_get_path("interfaces/{$interface}");
7235
	if ($iface) {
7236
		if (($family == 4) && ($iface['ipaddr'] == "dhcp")) {
7237
			return true;
7238
		} elseif (($family == 6) && ($iface['ipaddrv6'] == "dhcp6")) {
7239
			return true;
7240
		} else {
7241
			return false;
7242
		}
7243
	}
7244

    
7245
	if ($family == 6) {
7246
		$dhcp_string = "_DHCP6";
7247
	} else {
7248
		$dhcp_string = "_DHCP";
7249
	}
7250

    
7251
	foreach (config_get_path('gateways/gateway_group', []) as $group) {
7252
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7253
			continue;
7254
		}
7255
		foreach ($group['item'] as $item) {
7256
			$item_data = explode("|", $item);
7257
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7258
				return true;
7259
			}
7260
		}
7261
	}
7262

    
7263
	return false;
7264
}
7265

    
7266
function remove_ifindex($ifname) {
7267
	return preg_replace("/[0-9]+$/", "", $ifname);
7268
}
7269

    
7270
function get_configured_vip_list_with_descr($family = 'all', $type = VIP_ALL) {
7271
	$interfaces = array();	// In case there are no VIPs defined
7272

    
7273
	$viplist = get_configured_vip_list($family, $type);
7274
	foreach ($viplist as $vipid => $address) {
7275
		$interfaces[$vipid] = $address;
7276
		if ($type = VIP_CARP) {
7277
			$vip = get_configured_vip($vipid);
7278
			if (isset($vip) && is_array($vip) ) {
7279
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7280
			}
7281
		}
7282
		if (get_vip_descr($address)) {
7283
			$interfaces[$vipid] .= " (" . get_vip_descr($address) . ")";
7284
		}
7285
	}
7286
	return $interfaces;
7287
}
7288

    
7289
function return_gateway_groups_array_with_descr() {
7290
	$interfaces = array();
7291
	$grouplist = return_gateway_groups_array();
7292
	foreach (array_keys($grouplist) as $name) {
7293
		$interfaces[$name] = "GW Group {$name}";
7294
	}
7295
	return $interfaces;
7296
}
7297

    
7298
function get_serial_ports($short=false) {
7299
	$linklist = array();
7300
	if (!is_dir("/var/spool/lock")) {
7301
		mwexec("/bin/mkdir -p /var/spool/lock");
7302
	}
7303
	$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);
7304
	foreach ($serialports as $port) {
7305
		$port = trim($port);
7306
		$port = ($short) ? basename($port) : $port;
7307
		$linklist[$port] = $port;
7308
	}
7309
	return $linklist;
7310
}
7311

    
7312
function get_interface_ports() {
7313
	$linklist = array();
7314
	$portlist = get_interface_list();
7315

    
7316
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
7317
		if (empty($vlan)) {
7318
			continue;
7319
		}
7320
		$portlist[$vlan['vlanif']] = $vlan;
7321
	}
7322

    
7323
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
7324
		if (empty($qinq)) {
7325
			continue;
7326
		}
7327
		$members = explode(" ", $qinq['members']);
7328
		foreach ($members as $mem) {
7329
			$qentry = $qinq['vlanif'] . "." . $mem;
7330
			$portlist[$qentry] = $qentry;
7331
		}
7332
	}
7333

    
7334
	foreach ($portlist as $ifn => $ifinfo) {
7335
		$string = "";
7336
		if (is_array($ifinfo)) {
7337
			$string .= $ifn;
7338
			if ($ifinfo['mac']) {
7339
				$string .= " ({$ifinfo['mac']})";
7340
			}
7341
			if ($ifinfo['friendly']) {
7342
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7343
			} elseif ($ifinfo['descr']) {
7344
				$string .= " - {$ifinfo['descr']}";
7345
			}
7346
		} else {
7347
			$string .= $ifinfo;
7348
		}
7349

    
7350
		$linklist[$ifn] = $string;
7351
	}
7352
	return $linklist;
7353
}
7354

    
7355
function build_ppps_link_list() {
7356
	global $pconfig;
7357

    
7358
	$linklist = array('list' => array(), 'selected' => array());
7359

    
7360
	if ($pconfig['type'] == 'ppp') {
7361
		$linklist['list'] = get_serial_ports();
7362
	} else {
7363
		$iflist = get_interface_ports();
7364

    
7365
		$viplist = array();
7366
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7367
		foreach ($carplist as $vid => $vaddr) {
7368
			$vip = get_configured_vip($vid);
7369
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7370
		}
7371

    
7372
		$linklist['list'] = array_merge($iflist, $viplist);
7373

    
7374
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7375
		$lagglist = get_lagg_interface_list();
7376
		foreach ($lagglist as $lagg) {
7377
			/* LAGG members cannot be assigned */
7378
			$laggmembers = explode(',', $lagg['members']);
7379
			foreach ($laggmembers as $lagm) {
7380
				if (isset($linklist['list'][$lagm])) {
7381
					unset($linklist['list'][$lagm]);
7382
				}
7383
			}
7384
		}
7385
	}
7386

    
7387
	$selected_ports = array();
7388
	if (is_array($pconfig['interfaces'])) {
7389
		$selected_ports = $pconfig['interfaces'];
7390
	} elseif (!empty($pconfig['interfaces'])) {
7391
		$selected_ports = explode(',', $pconfig['interfaces']);
7392
	}
7393
	foreach ($selected_ports as $port) {
7394
		if (isset($linklist['list'][$port])) {
7395
			array_push($linklist['selected'], $port);
7396
		}
7397
	}
7398
	return($linklist);
7399
}
7400

    
7401
function create_interface_list($open = false) {
7402
	$iflist = array();
7403

    
7404
	// add group interfaces
7405
	config_get_path('ifgroups/ifgroupentry', []);
7406
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $ifgen) {
7407
		if ($open || have_ruleint_access($ifgen['ifname'])) {
7408
			$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7409
		}
7410
	}
7411

    
7412
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7413
		if ($open || have_ruleint_access($ifent)) {
7414
			$iflist[$ifent] = $ifdesc;
7415
		}
7416
	}
7417

    
7418
	if (config_get_path('l2tp/mode', "") == "server" && ($open || have_ruleint_access("l2tp"))) {
7419
		$iflist['l2tp'] = gettext('L2TP VPN');
7420
	}
7421

    
7422
	if (is_pppoe_server_enabled() && ($open || have_ruleint_access("pppoe"))) {
7423
		$iflist['pppoe'] = gettext("PPPoE Server");
7424
	}
7425

    
7426
	// add ipsec interfaces
7427
	if (ipsec_enabled() && ($open || have_ruleint_access("enc0"))) {
7428
		$iflist["enc0"] = gettext("IPsec");
7429
	}
7430

    
7431
	// add openvpn/tun interfaces
7432
	if (config_get_path('openvpn/openvpn-server') || config_get_path('openvpn/openvpn-client')) {
7433
		$iflist["openvpn"] = gettext("OpenVPN");
7434
	}
7435

    
7436
	return($iflist);
7437
}
7438

    
7439
function is_pseudo_interface($inf, $tap=true) {
7440
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7441
	foreach ($psifs as $pif) {
7442
		if (substr($inf, 0, strlen($pif)) == $pif) {
7443
			if (($pif == 'ovpn') && $tap) {
7444
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7445
				$type = ($m[1] == 'c') ? 'client' : 'server';
7446
				foreach (config_get_path("openvpn/openvpn-{$type}", []) as $ovpn) {
7447
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7448
						return false;
7449
					} elseif ($ovpn['vpnid'] == $m[2]) {
7450
						return true;
7451
					}
7452
				}
7453
			} else {
7454
				return true;
7455
			}
7456
		}
7457
	}
7458
	return false;
7459
}
7460

    
7461
function is_stf_interface($inf) {
7462
	switch (config_get_path("interfaces/{$inf}/ipaddrv6")) {
7463
		case '6rd':
7464
		case '6to4':
7465
			return true;
7466
		default:
7467
			return false;
7468
	}
7469
}
7470

    
7471
function restart_interface_services($interface, $ipv6type = "") {
7472

    
7473
	services_unbound_configure(true, $interface);
7474

    
7475
	services_igmpproxy_configure($interface);
7476
	services_snmpd_configure($interface);
7477
	vpn_l2tp_configure($interface);
7478

    
7479
	if (substr(config_get_path("interfaces/{$interface}/if",""), 0, 4) != "ovpn") {
7480
		openvpn_resync_all($interface);
7481
	}
7482
	ipsec_force_reload($interface);
7483

    
7484
	/* restart RADVD to announce correct IPv6 prefix
7485
	 * see https://redmine.pfsense.org/issues/12604 */ 
7486
	if ((($ipv6type == "staticv6") || ($ipv6type == "track6")) &&
7487
	    (config_get_path("dhcpdv6/{$interface}/ramode", "disabled") != "disabled")) {
7488
		services_radvd_configure();
7489
	}
7490

    
7491
	if (config_path_enabled("dhcpd/{$interface}") ||
7492
	    config_path_enabled("dhcpdv6/{$interface}")) {
7493
		services_dhcpd_configure();
7494
	}
7495

    
7496
	init_config_arr(array('syslog'));
7497
	if (config_path_enabled('syslog') && ($interface == config_get_path('syslog/sourceip'))) {
7498
		system_syslogd_start();
7499
	}
7500
}
7501

    
7502
/**
7503
 * Return interface parameters and primary ipv4 and ipv6 addresses for the real iface
7504
 * $interface, identified by exclusion of VIPs. Deprecates pfSense_get_interface_addresses()
7505
 *
7506
 * Result array contains keyed values:
7507
 * - ipaddr: ipv4 address
7508
 * - subnetbits: ipv4 subnet bits
7509
 * - subnet: ipv4 subnet
7510
 * - broadcast: ipv4 broadcast addr (if applicable)
7511
 * - tunnel: ipv4 PPP endpoint (if applicable)
7512
 * - ipaddr6: ipv6 address
7513
 * - tentative: ipv6 tentative flag (if applicable)
7514
 * - subnetbits6: ipv6 subnet bits
7515
 * - tunnel6: ipv6 tunnel endpoint
7516
 * - status: up or down interface status
7517
 * - link0: per link layer defined flag
7518
 * - link1: per link layer defined flag
7519
 * - link2: per link layer defined flag
7520
 * - multicast: multicast support
7521
 * - loopback: interface is a loopback interface
7522
 * - pointtopoint: interface is point-to-point
7523
 * - promisc: interface in promisc mode
7524
 * - permanentpromisc: interface permanently in promisc mode
7525
 * - oactive: interface tx hardware queue is full
7526
 * - allmulti: interface receives all multicast packets
7527
 * - simplex: interface is simplex
7528
 * - linkstateup: interface link is up
7529
 * - iftype: wireless, ether, vlan, bridge, virtual, other
7530
 * - mtu: mtu of interface
7531
 * - caps: interface capabilities array
7532
 * - encaps: enabled capabilities array
7533
 * - macaddr: interface configured ethernet address
7534
 * - hwaddr: hardware ethernet address
7535
 */
7536
function get_interface_addresses($interface) {
7537
	$v4addrs = array();
7538
	$v6addrs = array();
7539
	$v4vips = array();
7540
	$v6vips = array();
7541
	$ifaddrs = pfSense_get_ifaddrs($interface);
7542

    
7543
	foreach (array_keys(get_configured_vip_list()) as $viface) {
7544
		$vip = get_configured_vip($viface);
7545
		if (is_ipaddrv4($vip['subnet'])) {
7546
			array_push($v4vips, $vip['subnet']);
7547
		} else if (is_ipaddrv6($vip['subnet'])) {
7548
			array_push($v6vips, $vip['subnet']);
7549
		}
7550
	}
7551

    
7552
	if ($ifaddrs['addrs']) {
7553
	   $v4addrs = array_filter($ifaddrs['addrs'], function($addr) use ($v4vips){
7554
		  return (array_search($addr['addr'], $v4vips) === false);
7555
	   });
7556
	}
7557

    
7558
	if ($ifaddrs['addrs6']) {
7559
	   $v6addrs = array_filter($ifaddrs['addrs6'], function($addr) use ($v6vips){
7560
		  return (array_search($addr['addr'], $v6vips) === false);
7561
	   });
7562
	}
7563
	/* Transform output to conform to pfSense_get_interface_addresses() */
7564
	if ($v4addrs) {
7565
		$v4addr = array_pop($v4addrs);
7566
		$ifaddrs['ipaddr'] = $v4addr['addr'];
7567
		foreach(array("subnetbits", "subnet", "broadcast", "tunnel") as $key) {
7568
			if (array_key_exists($key, $v4addr)) {
7569
				$ifaddrs[$key] = $v4addr[$key];
7570
			}
7571
		}
7572
	}
7573

    
7574
	if ($v6addrs) {
7575
		$v6addr = array_pop($v6addrs);
7576
		$ifaddrs['ipaddr6'] = $v6addr['addr'];
7577
		foreach(array("subnetbits", "tunnel") as $key) {
7578
			if (array_key_exists($key, $v6addr)) {
7579
				$ifaddrs[$key.'6'] = $v6addr[$key];
7580
			}
7581
		}
7582
		if (array_key_exists('tentative', $v6addr)) {
7583
			$ifaddrs['tentative'] = $v6addr['tentative'];
7584
		}
7585
	}
7586
	unset($ifaddrs['addrs']);
7587
	unset($ifaddrs['addrs6']);
7588

    
7589
	return($ifaddrs);
7590
}
7591
?>
(23-23/62)