Project

General

Profile

Download (223 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-2024 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 (is_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 (is_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
/**
344
 * Configure the child VLAN interfaces for a parent interface.
345
 * 
346
 * @param bool $skip_parent_mtu Skip setting the parent interface's MTU
347
 */
348
function interfaces_vlan_configure($parentif = "", $skip_parent_mtu = false) {
349
	$dhcp6c_list = array();
350

    
351
	$vlans = config_get_path('vlans/vlan');
352
	if (is_array($vlans) && count($vlans)) {
353
		// If the parent MTU is being skipped at boot, this has already been shown
354
		if (is_platform_booting() && !$skip_parent_mtu) {
355
			echo gettext("Configuring VLAN interfaces...");
356
		}
357
		foreach ($vlans as $vlan) {
358
			if (empty($vlan['vlanif'])) {
359
				$vlan['vlanif'] = vlan_interface($vlan);
360
			}
361
			if (!empty($parentif) && ($parentif != $vlan['if'])) {
362
				continue;
363
			}
364
			/* configure dhcp6 enabled VLAN interfaces later
365
			 * see https://redmine.pfsense.org/issues/3965 */
366
			$if = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
367
			if (config_get_path("interfaces/{$if}/ipaddrv6", "") == "dhcp6") {
368
				$dhcp6c_list[$if] = $vlan;
369
				continue;
370
			}
371

    
372
			/* XXX: Maybe we should report any errors?! */
373
			interface_vlan_configure($vlan, false, $skip_parent_mtu);
374
		}
375
		foreach ($dhcp6c_list as $if => $vlan) {
376
			interface_vlan_configure($vlan, false, $skip_parent_mtu);
377
		}
378
		/* Invalidate cache */
379
		get_interface_arr(true);
380
		// If the parent MTU is being skipped at boot, this has already been shown
381
		if (is_platform_booting() && !$skip_parent_mtu) {
382
			echo gettext("done.") . "\n";
383
		}
384
	}
385
}
386

    
387
/**
388
 * Configure a VLAN interface.
389
 * 
390
 * @param bool $skip_parent_mtu Skip setting the parent interface's MTU
391
 */
392
function interface_vlan_configure(&$vlan, $flush = true, $skip_parent_mtu = false) {
393
	if (!is_array($vlan)) {
394
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
395
		return(NULL);
396
	}
397
	$if = $vlan['if'];
398
	if (empty($if)) {
399
		log_error(gettext("interface_vlan_configure called with if undefined."));
400
		return(NULL);
401
	}
402

    
403
	$vlanif = empty($vlan['vlanif']) ? vlan_interface($vlan) : $vlan['vlanif'];
404
	if ($vlanif == NULL) {
405
		log_error(gettext("vlan_interface called with if undefined var."));
406
		return(NULL);
407
	}
408
	$tag = $vlan['tag'];
409
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
410

    
411
	/* make sure the parent interface is up */
412
	interfaces_bring_up($if);
413
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
414
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
415

    
416
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
417
		pfSense_interface_destroy($vlanif);
418
	}
419

    
420
	$tmpvlanif = pfSense_interface_create2("vlan");
421
	if (!is_string($tmpvlanif)) {
422
		log_error(sprintf(gettext('Failed to configure interface %1$s: Could not create temporary interface %2$s'), $vlan['vlanif'], 'vlan'));
423
		return(NULL);
424
	}
425
	pfSense_interface_rename($tmpvlanif, $vlanif);
426
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
427

    
428
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
429

    
430
	interfaces_bring_up($vlanif);
431

    
432
	/* invalidate interface cache */
433
	if ($flush) {
434
		get_interface_arr(true);
435
	}
436

    
437
	/* configure interface if assigned */
438
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
439
	if ($assignedif) {
440
		if (config_path_enabled("interfaces/{$assignedif}")) {
441
			interface_configure($assignedif, true, false, $skip_parent_mtu);
442
		}
443
	}
444

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

    
448
	if (interface_vlan_mtu_configured($vlanif)) {
449
		set_interface_mtu($vlanif, interface_vlan_mtu_configured($vlanif));
450
	}
451

    
452
	return $vlanif;
453
}
454

    
455
/*
456
 * reconfigure VLAN childs interfaces after MTU changes, see
457
 * https://redmine.pfsense.org/issues/11035
458
 */
459
function interfaces_vlan_configure_mtu($parentif = "") {
460
	config_init_path('ppps/ppp');
461
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
462
		if ($parentif != $vlan['if']) {
463
			continue;
464
		}
465
		if (interface_vlan_mtu_configured($vlan['vlanif'])) {
466
		       set_interface_mtu($vlan['vlanif'],
467
			   interface_vlan_mtu_configured($vlan['vlanif']));
468
		}
469
		if (empty(config_get_path('ppps/ppp'))) {
470
			continue;
471
		}
472
		// PPP interfaces must be restarted to adjust MTU changes
473
		foreach (config_get_path('ppps/ppp', []) as $ppp) {
474
			$ports = explode(',', $ppp['ports']);
475
			foreach ($ports as $port) {
476
				if ($port != $vlan['vlanif']) {
477
					continue;
478
				}
479
				$confif = convert_real_interface_to_friendly_interface_name($ppp['if']);
480
				interface_configure($confif);
481
			}
482
		}
483
	}
484
}
485

    
486
function interface_qinq_configure(&$qinq, $flush = true) {
487
	global $g;
488

    
489
	if (!is_array($qinq)) {
490
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
491
		return;
492
	}
493

    
494
	$qinqif = $qinq['if'];
495
	if (empty($qinqif)) {
496
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
497
		return;
498
	}
499

    
500
	if (!does_interface_exist($qinqif)) {
501
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
502
		return;
503
	}
504

    
505
	$vlanif = interface_vlan_configure($qinq);
506
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
507
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
508
		return;
509
	}
510

    
511
	exec("/sbin/ifconfig {$vlanif} vlanproto 802.1ad > /dev/null 2>&1");
512

    
513
	/* make sure the parent is up */
514
	interfaces_bring_up($qinqif);
515

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

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

    
525
	$macaddr = get_interface_mac($qinqif);
526
	if (!empty($qinq['members'])) {
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, $macaddr);
533
			unset($qinq2);
534
		}
535
	}
536

    
537
	interfaces_bring_up($qinqif);
538
	if (!empty($qinq['members'])) {
539
		$members = explode(" ", $qinq['members']);
540
		foreach ($members as $qtag) {
541
			interfaces_bring_up(qinq_interface($qinq, $qtag));
542
		}
543
	}
544

    
545
	return $vlanif;
546
}
547

    
548
function interfaces_qinq_configure($ovpn=false) {
549
	$qinqentry = config_get_path('qinqs/qinqentry');
550
	if (is_array($qinqentry) && count($qinqentry)) {
551
		if (is_platform_booting() && $ovpn) {
552
			echo gettext("Configuring OpenVPN QinQ interfaces...");
553
		} elseif (is_platform_booting()) {
554
			echo gettext("Configuring QinQ interfaces...");
555
		}
556
		foreach ($qinqentry as $qinq) {
557
			if (($ovpn && strstr($qinq['if'], "ovpn")) ||
558
			    (!$ovpn && !strstr($qinq['if'], "ovpn"))) {
559
				interface_qinq_configure($qinq, false);
560
			}
561
		}
562
		/* Invalidate cache */
563
		get_interface_arr(true);
564
		if (is_platform_booting()) {
565
			echo gettext("done.") . "\n";
566
		}
567
	}
568
}
569

    
570
function interface_qinq2_configure(&$qinq, $macaddr) {
571
	if (!is_array($qinq)) {
572
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
573
		return;
574
	}
575

    
576
	$if = $qinq['if'];
577
	if (empty($if)) {
578
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
579
		return;
580
	}
581
	$tag = $qinq['tag'];
582
	$vlanif = "{$if}.{$tag}";
583
	$ngif = str_replace(".", "_", $if);
584
	if (strlen($vlanif) > IF_NAMESIZE) {
585
		log_error(sprintf(gettext("interface_qinq2_configure interface name too big %s. (max. size: %d).%s"),
586
		    $vlanif, IF_NAMESIZE, "\n"));
587
		return;
588
	}
589

    
590
	exec("/sbin/ifconfig vlan create vlandev {$if} vlan {$tag} name {$vlanif}");
591

    
592
	return $vlanif;
593
}
594

    
595
function interfaces_create_wireless_clones() {
596
	$iflist = get_configured_interface_list();
597

    
598
	foreach ($iflist as $if) {
599
		$realif = config_get_path("interfaces/{$if}/if");
600
		if (!is_interface_wireless($realif)) {
601
			continue;
602
		}
603
		interface_wireless_clone(interface_get_wireless_clone($realif),
604
								 config_get_path("interfaces/{$if}"));
605
	}
606

    
607
	$wclone = config_get_path('wireless/clone');
608
	if (is_array($wclone) && count($wclone)) {
609
		if (is_platform_booting()) {
610
			echo gettext("Creating wireless clone interfaces...");
611
		}
612
		/* Invalidate cache */
613
		get_interface_arr(true);
614
		foreach ($wclone as $clone) {
615
			if (empty($clone['cloneif'])) {
616
				continue;
617
			}
618
			if (does_interface_exist($clone['cloneif'])) {
619
				continue;
620
			}
621
			/* XXX: Maybe we should report any errors?! */
622
			interface_wireless_clone($clone['cloneif'], $clone);
623
		}
624
		if (is_platform_booting()) {
625
			echo gettext("done.") . "\n";
626
		}
627
	}
628
}
629

    
630
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
631
	$bridged = config_get_path('bridges/bridged');
632
	if (!is_array($bridged) || !count($bridged)) {
633
		return;
634
	}
635

    
636
	$i = 0;
637
	foreach ($bridged as $bridge) {
638
		if (empty($bridge['bridgeif'])) {
639
			$bridge['bridgeif'] = "bridge{$i}";
640
		}
641
		if (!empty($realif) && ($realif != $bridge['bridgeif'])) {
642
			continue;
643
		}
644
		$ifname = false;
645
		foreach (config_get_path('interfaces', []) as $intname => $intpar) {
646
			if ($intpar['if'] == $bridge['bridgeif']) {
647
				$ifname = $intname;
648
				break;
649
			}
650
		}
651

    
652
		if ($ifname && (config_get_path("interfaces/{$ifname}/ipaddrv6", "") == "track6")) {
653
			if ($checkmember == 1) {
654
				continue;
655
			} else {
656
				$checkmember = 0;
657
			}
658
		} elseif (($checkmember == 2) && !$ifname) {
659
			continue;
660
		}
661

    
662
		/* XXX: Maybe we should report any errors?! */
663
		interface_bridge_configure($bridge, $checkmember, false);
664
		$i++;
665
	}
666

    
667
	/* Invalidate cache */
668
	get_interface_arr(true);
669
}
670

    
671
function interface_bridge_configure(&$bridge, $checkmember = 0, $flush = true) {
672
	if (!is_array($bridge)) {
673
		return;
674
	}
675

    
676
	if (empty($bridge['members'])) {
677
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
678
		return;
679
	}
680

    
681
	$members = explode(',', $bridge['members']);
682
	if (!count($members)) {
683
		return;
684
	}
685

    
686
	/* Calculate smaller mtu and enforce it */
687
	$smallermtu = 0;
688
	$foundgif = false;
689
	foreach ($members as $member) {
690
		$realif = get_real_interface($member);
691
		$mtu = get_interface_mtu($realif);
692
		if (substr($realif, 0, 3) == "gif") {
693
			$foundgif = true;
694
			if ($checkmember == 1) {
695
				return;
696
			}
697
			if ($mtu <= 1500) {
698
				continue;
699
			}
700
		}
701
		if ($smallermtu == 0 && !empty($mtu)) {
702
			$smallermtu = $mtu;
703
		} elseif (!empty($mtu) && $mtu < $smallermtu) {
704
			$smallermtu = $mtu;
705
		}
706
	}
707
	if ($foundgif == false && $checkmember == 2) {
708
		return;
709
	}
710

    
711
	/* Just in case anything is not working well */
712
	if ($smallermtu == 0) {
713
		$smallermtu = 1500;
714
	}
715

    
716
	if (!empty($bridge['bridgeif'])) {
717
		pfSense_interface_destroy($bridge['bridgeif']);
718
		$tempifname = pfSense_interface_create2($bridge['bridgeif']);
719
		if (!is_string($tempifname)) {
720
			log_error(sprintf(gettext('Failed to configure interface %1$s: Could not create temporary interface %2$s'), $bridge['bridgeif'], $bridge['bridgeif']));
721
			return;
722
		}
723
		$bridgeif = escapeshellarg($bridge['bridgeif']);
724
	} else {
725
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
726
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
727
		$bridgeif = pfSense_interface_create2("bridge");
728
		if (!is_string($bridgeif)) {
729
			log_error(sprintf(gettext('Failed to configure interface %1$s: Could not create temporary interface %2$s'), $bridge['bridgeif'], 'bridge'));
730
			return;
731
		}
732
		$bridge['bridgeif'] = $bridgeif;
733
	}
734

    
735
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
736
	if ($bridgemtu > $smallermtu) {
737
		$smallermtu = $bridgemtu;
738
	}
739

    
740
	$checklist = get_configured_interface_list();
741

    
742
	/* Add interfaces to bridge */
743
	foreach ($members as $member) {
744
		if (empty($checklist[$member])) {
745
			continue;
746
		}
747
		$realif = get_real_interface($member);
748
		if (!$realif) {
749
			log_error(gettext("realif not defined in interfaces bridge - up"));
750
			continue;
751
		}
752
		/* make sure the parent interface is up */
753
		pfSense_interface_mtu($realif, $smallermtu);
754
		interfaces_bring_up($realif);
755
		enable_hardware_offloading($member);
756
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
757
	}
758

    
759
	if (isset($bridge['enablestp'])) {
760
		interface_bridge_configure_stp($bridge);
761
	}
762

    
763
	interface_bridge_configure_advanced($bridge);
764

    
765
	interface_bridge_configure_ip6linklocal($bridge);
766

    
767
	if ($flush) {
768
		get_interface_arr(true);
769
	}
770

    
771
	if ($bridge['bridgeif']) {
772
		interfaces_bring_up($bridge['bridgeif']);
773
	} else {
774
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
775
	}
776
}
777

    
778
function interface_bridge_configure_stp($bridge) {
779
	if (isset($bridge['enablestp'])) {
780
		$bridgeif = escapeshellarg(trim($bridge['bridgeif']));
781
		/* configure spanning tree proto */
782
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
783

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

    
837
function interface_bridge_configure_advanced($bridge) {
838
	$bridgeif = escapeshellarg(trim($bridge['bridgeif']));
839

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

    
897
function interface_bridge_configure_ip6linklocal($bridge) {
898
	$bridgeif = escapeshellarg(trim($bridge['bridgeif']));
899

    
900
	$members = explode(',', $bridge['members']);
901
	if (!count($members)) {
902
		return;
903
	}
904

    
905
	$auto_linklocal = isset($bridge['ip6linklocal']);
906
	$bridgeop = $auto_linklocal ? '' : '-';
907
	$memberop = $auto_linklocal ? '-' : '';
908

    
909
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
910
	foreach ($members as $member) {
911
		$realif = escapeshellarg(get_real_interface($member));
912
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
913
	}
914
}
915

    
916
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
917
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
918
		return;
919
	}
920

    
921
	if ($flagsapplied == false) {
922
		$mtu = get_interface_mtu($bridgeif);
923
		$mtum = get_interface_mtu($interface);
924
		/* Reconfigure the bridge mtu if the new member's MTU is lower, or
925
		 * reconfigure a non-gif interface MTU if the bridge's MTU is lower */
926
		if ($mtu > $mtum) {
927
			pfSense_interface_mtu($bridgeif, $mtum);
928
		} else if ($mtu < $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
929
			pfSense_interface_mtu($interface, $mtu);
930
		}
931

    
932
		hardware_offloading_applyflags($interface);
933
		interfaces_bring_up($interface);
934
	}
935

    
936
	pfSense_bridge_add_member($bridgeif, $interface);
937
	$bridged = config_get_path('bridges/bridged');
938
	if (is_array($bridged)) {
939
		foreach ($bridged as $bridge) {
940
			if ($bridgeif == $bridge['bridgeif']) {
941
				interface_bridge_configure_stp($bridge);
942
				interface_bridge_configure_advanced($bridge);
943
			}
944
		}
945
	}
946
}
947

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

    
974
function interface_lagg_configure($lagg, $flush = true) {
975
	if (!is_array($lagg)) {
976
		return -1;
977
	}
978

    
979
	$members = explode(',', $lagg['members']);
980
	if (!count($members)) {
981
		return -1;
982
	}
983

    
984
	if (is_platform_booting() || !(empty($lagg['laggif']))) {
985
		pfSense_interface_destroy($lagg['laggif']);
986
		$tempifname = pfSense_interface_create2($lagg['laggif']);
987
		if (!is_string($tempifname)) {
988
			log_error(sprintf(gettext('Failed to configure interface %1$s: Could not create temporary interface %2$s'), $lagg['laggif'], $lagg['laggif']));
989
			return -1;
990
		}
991
		$laggif = $lagg['laggif'];
992
	} else {
993
		$laggif = pfSense_interface_create2("lagg");
994
		if (!is_string($laggif)) {
995
			log_error(sprintf(gettext('Failed to configure interface %1$s: Could not create temporary interface %2$s'), $lagg['laggif'], 'lagg'));
996
			return -1;
997
		}
998
	}
999

    
1000
	/* Check if MTU was defined for this lagg interface */
1001
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
1002
	if ($lagg_mtu == 0) {
1003
		foreach (config_get_path('interfaces', []) as $tmpinterface) {
1004
			// ignore the configured MTU from disabled interfaces
1005
			if (($tmpinterface['if'] == $lagg['laggif']) && isset($tmpinterface['enable']) &&
1006
			    !empty($tmpinterface['mtu'])) {
1007
				$lagg_mtu = $tmpinterface['mtu'];
1008
				break;
1009
			}
1010
		}
1011
	}
1012

    
1013
	/* Just in case anything is not working well */
1014
	if ($lagg_mtu == 0) {
1015
		$lagg_mtu = 1500;
1016
	}
1017

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

    
1025
	if (($lagg['proto'] == 'lacp') && isset($lagg['lacptimeout']) &&
1026
	    ($lagg['lacptimeout'] != 'slow')) {
1027
		$lacptimeout = 'lacp_fast_timeout';
1028
	} else {
1029
		$lacptimeout = '';
1030
	}
1031

    
1032
	if ((($lagg['proto'] == 'lacp') || ($lagg['proto'] == 'loadbalance')) &&
1033
	    isset($lagg['lagghash']) && !empty($lagg['lagghash'])) {
1034
		$lagghash = 'lagghash ' . escapeshellarg($lagg['lagghash']);
1035
	} else {
1036
		$lagghash = '';
1037
	}
1038

    
1039
	foreach ($members as $member) {
1040
		if (!does_interface_exist($member)) {
1041
			continue;
1042
		}
1043

    
1044
		/* make sure the parent interface is up */
1045
		pfSense_interface_mtu($member, $lagg_mtu);
1046
		interfaces_bring_up($member);
1047
		hardware_offloading_applyflags($member);
1048

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

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

    
1057
	if ($flush) {
1058
		get_interface_arr(true);
1059
	}
1060

    
1061
	interfaces_bring_up($laggif);
1062
	// after the lagg is recreated, its VLANs must be reconfigured
1063
	interfaces_vlan_configure($laggif, true);
1064

    
1065
	return $laggif;
1066
}
1067

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

    
1072
	if (!is_array($gre)) {
1073
		return -1;
1074
	}
1075

    
1076
	$realif = convert_friendly_interface_to_real_interface_name($gre['if']);
1077
	if (!interface_is_vlan($realif)) {
1078
		$realif = get_real_interface($gre['if']);
1079
	}
1080
	$realifip = get_interface_ip($gre['if']);
1081
	$realifip6 = get_interface_ipv6($gre['if']);
1082

    
1083
	/* do not run ifconfig without correct $realifip */
1084
	if ((!$realifip && is_ipaddrv4($gre['remote-addr'])) ||
1085
	    (!$realifip6 && is_ipaddrv6($gre['remote-addr']))) {
1086
		return -1;
1087
	}
1088

    
1089
	/* make sure the parent interface is up */
1090
	interfaces_bring_up($realif);
1091

    
1092
	if (is_platform_booting() || !(empty($gre['greif']))) {
1093
		pfSense_interface_destroy($gre['greif']);
1094
		$tempifname = pfSense_interface_create2($gre['greif']);
1095
		if (!is_string($tempifname)) {
1096
			log_error(sprintf(gettext('Failed to configure interface %1$s: Could not create temporary interface %2$s'), $gre['if'], $gre['greif']));
1097
			return -1;
1098
		}
1099
		$greif = $gre['greif'];
1100
	} else {
1101
		$greif = pfSense_interface_create2("gre");
1102
		if (!is_string($greif)) {
1103
			log_error(sprintf(gettext('Failed to configure interface %1$s: Could not create temporary interface %2$s'), $gre['if'], 'gre'));
1104
			return -1;
1105
		}
1106
	}
1107

    
1108
	$tunnel_type = '';
1109
	if ((!empty($gre['tunnel-local-addr'])) || (!empty($gre['tunnel-remote-addr']))) {
1110
		$tunnel_type = 'v4';
1111
	}
1112
	if ((!empty($gre['tunnel-local-addr6'])) || (!empty($gre['tunnel-remote-addr6']))) {
1113
		$tunnel_type .= 'v6';
1114
	}
1115

    
1116
	/* Do not change the order here for more see gre(4) NOTES section. */
1117
	if (is_ipaddrv6($gre['remote-addr'])) {
1118
		mwexec("/sbin/ifconfig " . escapeshellarg($greif) . " inet6 tunnel " . escapeshellarg($realifip6) . " " . escapeshellarg($gre['remote-addr']));
1119
	} else {
1120
		mwexec("/sbin/ifconfig " . escapeshellarg($greif) . " tunnel " . escapeshellarg($realifip) . " " . escapeshellarg($gre['remote-addr']));
1121
	}
1122
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1123
		mwexec("/sbin/ifconfig " . escapeshellarg($greif) . " " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
1124
	}
1125
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1126
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1127
		mwexec("/sbin/ifconfig " . escapeshellarg($greif) . " inet6 " . escapeshellarg($gre['tunnel-local-addr6']) . " " . escapeshellarg($gre['tunnel-remote-addr6']) . " prefixlen 128");
1128
	}
1129

    
1130
	$parentif = get_real_interface($gre['if']);
1131
	if ($parentif) {
1132
		interfaces_bring_up($parentif);
1133
	} else {
1134
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gre_configure()"));
1135
	}
1136

    
1137
	if (isset($gre['link1'])) {
1138
		if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1139
			mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1140
		}
1141
		if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1142
			mwexec("/sbin/route -6 add " . escapeshellarg($gre['tunnel-remote-addr6']) . "/" . escapeshellarg($gre['tunnel-remote-net6']) . " " . escapeshellarg($gre['tunnel-local-addr6']));
1143
		}
1144
	}
1145
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1146
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1147
		unlink_if_exists("{$g['tmp_path']}/{$greif}_router.last");
1148
	}
1149
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1150
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr6']);
1151
		unlink_if_exists("{$g['tmp_path']}/{$greif}_routerv6.last");
1152
	}
1153

    
1154
	if ($flush) {
1155
		get_interface_arr(true);
1156
	}
1157

    
1158
	interfaces_bring_up($greif);
1159

    
1160
	return $greif;
1161
}
1162

    
1163
function interface_is_type($if, $type) {
1164
	switch ($type) {
1165
		case "gre":
1166
			$list = 'gres';
1167
			$entry = 'gre';
1168
			$entif = 'greif';
1169
			break;
1170
		case "gif":
1171
			$list = 'gifs';
1172
			$entry = 'gif';
1173
			$entif = 'gifif';
1174
			break;
1175
		case "lagg":
1176
			$list = 'laggs';
1177
			$entry = 'lagg';
1178
			$entif = 'laggif';
1179
			break;
1180
		default:
1181
			break;
1182
	}
1183

    
1184
	$entries = config_get_path("{$list}/{$entry}");
1185
	if (!is_array($entries)) {
1186
		return (NULL);
1187
	}
1188

    
1189
	foreach ($entries as $ent) {
1190
		if ($ent[$entif] == $if) {
1191
			return ($ent);
1192
		}
1193
	}
1194
	return (NULL);
1195
}
1196

    
1197
function is_greipsec($if) {
1198
	if (ipsec_enabled()) {
1199
		foreach (config_get_path('gres/gre', []) as $gre) {
1200
			foreach (config_get_path('ipsec/phase1', []) as $ph1ent) {
1201
				foreach (config_get_path('ipsec/phase2', []) as $ph2ent) {
1202
					if (($ph1ent['ikeid'] == $ph2ent['ikeid']) && ($ph2ent['mode'] == 'transport') &&
1203
					    !isset($ph1ent['disabled']) && !isset($ph2ent['disabled']) &&
1204
					    ($ph1ent['interface'] == $gre['if']) && ($gre['greif'] == $if) &&
1205
					    ($ph1ent['remote-gateway'] == $gre['remote-addr'])) {
1206
						    return true;
1207
					}
1208
				}
1209
			}
1210
		}
1211
	}
1212
	return false;
1213
}
1214

    
1215
/* NOTE: $gifkey is not used but useful for passing this function to array_walk. */
1216
function interface_gif_configure(&$gif, $gifkey = "", $flush = true) {
1217
	global $g;
1218
	if (!is_array($gif)) {
1219
		return -1;
1220
	}
1221

    
1222
	$realif = convert_friendly_interface_to_real_interface_name($gif['if']);
1223
	if (!interface_is_vlan($realif)) {
1224
		$realif = get_real_interface($gif['if']);
1225
	}
1226
	$ipaddr = get_interface_ip($gif['if']);
1227

    
1228
	if (is_ipaddrv4($gif['remote-addr'])) {
1229
		if (is_ipaddrv4($ipaddr)) {
1230
			$realifip = $ipaddr;
1231
		} else {
1232
			$realifip = get_interface_ip($gif['if']);
1233
		}
1234
		$realifgw = get_interface_gateway($gif['if']);
1235
	} elseif (is_ipaddrv6($gif['remote-addr'])) {
1236
		if (is_ipaddrv6($ipaddr)) {
1237
			$realifip = $ipaddr;
1238
		} else {
1239
			$realifip = get_interface_ipv6($gif['if']);
1240
		}
1241
		$realifgw = get_interface_gateway_v6($gif['if']);
1242
	}
1243

    
1244
	/* do not run ifconfig without correct $realifip */
1245
	if ((!is_ipaddrv4($realifip) && is_ipaddrv4($gif['remote-addr'])) ||
1246
	    (!is_ipaddrv6($realifip) && is_ipaddrv6($gif['remote-addr']))) {
1247
		return -1;
1248
	}
1249

    
1250
	/* make sure the parent interface is up */
1251
	$parentif = get_real_interface($gif['if']);
1252
	if ($parentif) {
1253
		interfaces_bring_up($parentif);
1254
	} else {
1255
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gif_configure()"));
1256
	}
1257

    
1258
	/* some kernels may need to load if_gif */
1259
	if (!is_module_loaded("if_gif")) {
1260
		mwexec("/sbin/kldload if_gif");
1261
	}
1262

    
1263
	if (is_platform_booting() || !(empty($gif['gifif']))) {
1264
		pfSense_interface_destroy($gif['gifif']);
1265
		$tempifname = pfSense_interface_create2($gif['gifif']);
1266
		if (!is_string($tempifname)) {
1267
			log_error(sprintf(gettext('Failed to configure interface %1$s: Could not create temporary interface %2$s'), $gif['if'], $gif['gifif']));
1268
			return -1;
1269
		}
1270
		$gifif = $gif['gifif'];
1271
	} else {
1272
		$gifif = pfSense_interface_create2("gif");
1273
		if (!is_string($gifif)) {
1274
			log_error(sprintf(gettext('Failed to configure interface %1$s: Could not create temporary interface %2$s'), $gif['if'], 'gif'));
1275
			return -1;
1276
		}
1277
	}
1278

    
1279
	/* Do not change the order here for more see gif(4) NOTES section. */
1280
	if (is_ipaddrv6($gif['remote-addr'])) {
1281
		mwexec("/sbin/ifconfig " . escapeshellarg($gifif) . " inet6 tunnel " . escapeshellarg($realifip) . " " . escapeshellarg($gif['remote-addr']));
1282
	} else {
1283
		mwexec("/sbin/ifconfig " . escapeshellarg($gifif) . " tunnel " . escapeshellarg($realifip) . " " . escapeshellarg($gif['remote-addr']));
1284
	}
1285
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1286
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1287
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1288
		mwexec("/sbin/ifconfig " . escapeshellarg($gifif) . " inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1289
	} else {
1290
		mwexec("/sbin/ifconfig " . escapeshellarg($gifif) . " " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1291
	}
1292
	if (isset($gif['link1'])) {
1293
		pfSense_interface_flags($gifif, IFF_LINK1);
1294
	}
1295
	if (isset($gif['link2'])) {
1296
		pfSense_interface_flags($gifif, IFF_LINK2);
1297
	}
1298
	if ($gifif) {
1299
		interfaces_bring_up($gifif);
1300
		$gifmtu = "";
1301
		$currentgifmtu = get_interface_mtu($gifif);
1302
		foreach (config_get_path('interfaces', []) as $tmpinterface) {
1303
			if ($tmpinterface['if'] == $gifif) {
1304
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1305
					$gifmtu = $tmpinterface['mtu'];
1306
				}
1307
			}
1308
		}
1309
		if (is_numericint($gifmtu)) {
1310
			if ($gifmtu != $currentgifmtu) {
1311
				mwexec("/sbin/ifconfig " . escapeshellarg($gifif) . " mtu {$gifmtu}");
1312
			}
1313
		}
1314
	} else {
1315
		log_error(gettext("could not bring gifif up -- variable not defined"));
1316
	}
1317

    
1318
	if (!is_platform_booting()) {
1319
		$iflist = get_configured_interface_list();
1320
		foreach ($iflist as $ifname) {
1321
			$if = config_get_path("interfaces/{$ifname}/if", "");
1322
			if ($if == $gifif) {
1323
				if (get_interface_gateway($ifname)) {
1324
					system_routing_configure($ifname);
1325
					break;
1326
				}
1327
				if (get_interface_gateway_v6($ifname)) {
1328
					system_routing_configure($ifname);
1329
					break;
1330
				}
1331
			}
1332
		}
1333
	}
1334

    
1335

    
1336
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1337
		file_put_contents("{$g['tmp_path']}/{$gifif}_router",
1338
		    $gif['tunnel-remote-addr']);
1339
		unlink_if_exists("{$g['tmp_path']}/{$gifif}_router.last");
1340
	} elseif (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1341
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6",
1342
		    $gif['tunnel-remote-addr']);
1343
		unlink_if_exists("{$g['tmp_path']}/{$gifif}_routerv6.last");
1344
	}
1345

    
1346
	route_add_or_change($gif['remote-addr'], $realifgw);
1347

    
1348
	if ($flush) {
1349
		get_interface_arr(true);
1350
	}
1351

    
1352
	interfaces_bring_up($gifif);
1353

    
1354
	return $gifif;
1355
}
1356

    
1357
function interfaces_tunnel_configure($checkparent = 0, $realif = "", $type = "") {
1358
	if (!in_array($type, array('gre', 'gif'))) {
1359
		return;
1360
	}
1361

    
1362
	$tuns = config_get_path("{$type}s/{$type}");
1363
	if (!is_array($tuns) || !count($tuns)) {
1364
		return;
1365
	}
1366

    
1367
	foreach ($tuns as $i => $tunnel) {
1368
		if (empty($tunnel["{$type}if"])) {
1369
			$tunnel["{$type}if"] = $type . $i;
1370
		}
1371
		if (!empty($realif) && $realif != $tunnel["{$type}if"]) {
1372
			continue;
1373
		}
1374

    
1375
		$ipaddrv6 = config_get_path("interfaces/{$tunnel}/if/ipaddrv6");
1376
		if ($checkparent == 1) {
1377
			if (substr($tunnel['if'], 0, 4) == '_vip') {
1378
				continue;
1379
			}
1380
			if (substr($tunnel['if'], 0, 5) == '_lloc') {
1381
				continue;
1382
			}
1383

    
1384
			if ($ipaddrv6 == "track6") {
1385
				continue;
1386
			}
1387
		} elseif ($checkparent == 2) {
1388
			if ((substr($tunnel['if'], 0, 4) != '_vip' &&
1389
			    substr($tunnel['if'], 0, 5) != '_lloc') &&
1390
				$ipaddrv6 != "track6") {
1391
				continue;
1392
			}
1393
		}
1394
		if ($type == 'gif') {
1395
			interface_gif_configure($tunnel, "", false);
1396
		} elseif ($type == 'gre') {
1397
			interface_gre_configure($tunnel, "", false);
1398
		}
1399
	}
1400

    
1401
	/* Invalidate cache */
1402
	get_interface_arr(true);
1403
}
1404

    
1405
/* Build a list of IPsec interfaces */
1406
function interface_ipsec_vti_list_p1($ph1ent) {
1407
	$iface_list = array();
1408

    
1409
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array(config_get_path('ipsec/phase2'))) {
1410
		return $iface_list;
1411
	}
1412

    
1413
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1414
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1415
		return $iface_list;
1416
	}
1417

    
1418
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1419
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1420
		foreach ($vtisubnet_spec as $vtisub) {
1421
			$iface_list[ipsec_get_ifname($ph1ent, $vtisub['reqid'])] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1422
		}
1423
	} else {
1424
		/* For IKEv2, only create one interface with additional addresses as aliases */
1425
		$iface_list[ipsec_get_ifname($ph1ent)] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1426
	}
1427
	return $iface_list;
1428
}
1429
function interface_ipsec_vti_list_all() {
1430
	$iface_list = array();
1431
	$phase1 = config_get_path('ipsec/phase1');
1432
	$phase2 = config_get_path('ipsec/phase2');
1433
	if (is_array($phase1) && is_array($phase2)) {
1434
		foreach ($phase1 as $ph1ent) {
1435
			if ($ph1ent['disabled']) {
1436
				continue;
1437
			}
1438
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1439
		}
1440
	}
1441
	return $iface_list;
1442
}
1443

    
1444
function is_interface_ipsec_vti_assigned($phase2) {
1445
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1446
	$vti_interface = null;
1447
	$vtisubnet_spec = ipsec_vti($phase1, true);
1448
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1449
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1450
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1451
			foreach ($vtisubnet_spec as $vtisub) {
1452
				/* Is this for this P2? */
1453
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1454
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1455
					$vti_interface = ipsec_get_ifname($phase1, $vtisub['reqid']);
1456
				}
1457
			}
1458
		} else {
1459
			$vti_interface = ipsec_get_ifname($phase1);
1460
		}
1461
	}
1462
	/* Check if this interface is assigned */
1463
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1464
}
1465
function interface_ipsec_vti_configure($ph1ent) {
1466
	global $ipsec_reqid_base;
1467

    
1468
	if (empty($ph1ent) || !is_array($ph1ent) || empty(config_get_path('ipsec/phase2'))) {
1469
		return false;
1470
	}
1471

    
1472
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1473
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1474
		return false;
1475
	}
1476

    
1477
	$left_spec = ipsec_get_phase1_src($ph1ent);
1478

    
1479
	/* Attempt to resolve the remote gateway if needed */
1480
	$right_spec = ipsec_get_phase1_dst($ph1ent);
1481
	if (empty($right_spec)) {
1482
		/* Far end cannot be resolved */
1483
		return false;
1484
	}
1485

    
1486
	$iface_addrs = array();
1487
	$reqids = array();
1488

    
1489
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1490
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1491
		/* Form a single interface for each P2 entry */
1492
		foreach ($vtisubnet_spec as $vtisub) {
1493
			$ipsecif = ipsec_get_ifname($ph1ent, $vtisub['reqid']);
1494
			if (!is_array($iface_addrs[$ipsecif])) {
1495
				$iface_addrs[$ipsecif] = array();
1496
			}
1497
			$vtisub['alias'] = "";
1498
			$iface_addrs[$ipsecif][] = $vtisub;
1499
			$reqids[$ipsecif] = $vtisub['reqid'];
1500
		}
1501
	} else {
1502
		/* For IKEv2, only create one interface with additional addresses as aliases */
1503
		$ipsecif = ipsec_get_ifname($ph1ent);
1504
		if (!is_array($iface_addrs[$ipsecif])) {
1505
			$iface_addrs[$ipsecif] = array();
1506
		}
1507
		$have_v4 = false;
1508
		$have_v6 = false;
1509
		foreach ($vtisubnet_spec as $vtisub) {
1510
			// Alias stuff
1511
			$vtisub['alias'] = "";
1512
			if (is_ipaddrv6($vtisub['left'])) {
1513
				if ($have_v6) {
1514
					$vtisub['alias'] = " alias";
1515
				}
1516
				$have_v6 = true;
1517
			} else {
1518
				if ($have_v4) {
1519
					$vtisub['alias'] = " alias";
1520
				}
1521
				$have_v4 = true;
1522
			}
1523
			$iface_addrs[$ipsecif][] = $vtisub;
1524
		}
1525
		/* IKEv2 w/o Split uses the reqid of the first P2 */
1526
		$reqids[$ipsecif] = $vtisubnet_spec[0]['reqid'];
1527
	}
1528

    
1529
	foreach ($iface_addrs as $ipsecif => $addrs) {
1530
		if (!is_array($addrs)) {
1531
			continue;
1532
		}
1533
		// Create IPsec interface
1534
		if (does_interface_exist($ipsecif)) {
1535
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy");
1536
		}
1537
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsec_reqid_base + $reqids[$ipsecif]));
1538

    
1539
		/* Apply the outer tunnel addresses to the interface */
1540
		$inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
1541
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} tunnel " . escapeshellarg($left_spec) . " " . escapeshellarg($right_spec) . " up");
1542

    
1543
		/* Loop through all of the addresses for this interface and apply them as needed */
1544
		foreach ($addrs as $addr) {
1545
			// apply interface addresses
1546
			if (is_v6($addr['left'])) {
1547
				$inet = "inet6";
1548
				$gwtype = "v6";
1549
				$right = '';
1550
			} else {
1551
				$inet = "inet";
1552
				$gwtype = "";
1553
				$right = escapeshellarg((explode('/', $addr['right'], 2))[0]);
1554
			}
1555

    
1556
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . $right . $addr['alias']);
1557
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1558
			if (empty($addr['alias'])) {
1559
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", (explode('/', $addr['right'], 2))[0]);
1560
				unlink_if_exists("/tmp/{$ipsecif}_router{$gwtype}.last");
1561
			}
1562
		}
1563
		/* Check/set the MTU if the user configured a custom value.
1564
		 * https://redmine.pfsense.org/issues/9111 */
1565
		$currentvtimtu = get_interface_mtu($ipsecif);
1566
		foreach (config_get_path('interfaces', []) as $tmpinterface) {
1567
			if ($tmpinterface['if'] == $ipsecif) {
1568
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1569
					$vtimtu = $tmpinterface['mtu'];
1570
				}
1571
			}
1572
		}
1573
		if (is_numericint($vtimtu)) {
1574
			if ($vtimtu != $currentvtimtu) {
1575
				mwexec("/sbin/ifconfig {$ipsecif} mtu {$vtimtu}");
1576
			}
1577
		}
1578
		/* Add the VTI to the interface cache directly because calling 'get_interface_arr(true)' is expensive.
1579
		   See: https://redmine.pfsense.org/issues/15449 */
1580
		global $interface_arr_cache;
1581
		if (is_array($interface_arr_cache) && !in_array($ipsecif, $interface_arr_cache)) {
1582
			$interface_arr_cache[] = $ipsecif;
1583
		}
1584
		system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1585
	}
1586
	return true;
1587
}
1588

    
1589
function interfaces_ipsec_vti_configure() {
1590
	$bootmsg = false;
1591

    
1592
	foreach (config_get_path('ipsec/phase1', []) as $ph1ent) {
1593
		if ($ph1ent['disabled']) {
1594
			continue;
1595
		}
1596
		if (interface_ipsec_vti_configure($ph1ent) &&
1597
			!$bootmsg && is_platform_booting()) {
1598
			echo gettext("Configuring IPsec VTI interfaces...");
1599
			$bootmsg = true;
1600
		}
1601
	}
1602
	if (is_platform_booting() && $bootmsg) {
1603
		echo gettext("done.") . "\n";
1604
	}
1605
}
1606

    
1607
function interfaces_configure() {
1608
	global $g;
1609

    
1610
	/* Set up our loopback interface */
1611
	interfaces_loopback_configure();
1612

    
1613
	/* create the unconfigured wireless clones */
1614
	interfaces_create_wireless_clones();
1615

    
1616
	/* set up LAGG virtual interfaces */
1617
	interfaces_lagg_configure();
1618

    
1619
	/* set up VLAN virtual interfaces */
1620
	interfaces_vlan_configure();
1621

    
1622
	interfaces_qinq_configure(false);
1623

    
1624
	$iflist = get_configured_interface_with_descr();
1625
	$delayed_list = array();
1626
	$bridge_list = array();
1627
	$track6_list = array();
1628
	$dhcp6c_list = array();
1629

    
1630
	/* This is needed to speedup interfaces on bootup. */
1631
	$reload = false;
1632
	if (!is_platform_booting()) {
1633
		$reload = true;
1634
	}
1635

    
1636
	foreach ($iflist as $if => $ifname) {
1637
		$realif = config_get_path("interfaces/{$if}/if","");
1638
		$ipaddrv6 = config_get_path("interfaces/{$if}/ipaddrv6", "");
1639
		if (strstr($realif, "bridge")) {
1640
			$bridge_list[$if] = $ifname;
1641
		} elseif (strstr($realif, "gre")) {
1642
			$delayed_list[$if] = $ifname;
1643
		} elseif (strstr($realif, "gif")) {
1644
			$delayed_list[$if] = $ifname;
1645
		} elseif (strstr($realif, "ovpn")) {
1646
			continue;
1647
		} elseif (strstr($realif, "ipsec")) {
1648
			continue;
1649
		} elseif ($ipaddrv6 == "track6") {
1650
			$track6_list[$if] = $ifname;
1651
		} else {
1652
			/* do not run dhcp6c if track interface does not exists
1653
			 * see https://redmine.pfsense.org/issues/3965
1654
			 * and https://redmine.pfsense.org/issues/11633 */
1655
			if ($ipaddrv6 == "dhcp6") {
1656
				$tr6list = link_interface_to_track6($if);
1657
				if (is_array($tr6list) && !empty($tr6list)) {
1658
					$dhcp6c_list[$if] = $ifname;
1659
					continue;
1660
				}
1661
			}
1662
			if (is_platform_booting()) {
1663
				printf(gettext("Configuring %s interface..."),
1664
				    $ifname);
1665
			}
1666

    
1667
			if (g_get('debug')) {
1668
				log_error(sprintf(gettext("Configuring %s"),
1669
				    $ifname));
1670
			}
1671
			interface_configure($if, $reload);
1672
			if (is_platform_booting()) {
1673
				echo gettext("done.") . "\n";
1674
			}
1675
		}
1676
	}
1677

    
1678
	/*
1679
	 * NOTE: The following function parameter consists of
1680
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1681
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1682
	 */
1683

    
1684
	/* set up GRE virtual interfaces */
1685
	interfaces_tunnel_configure(1,'','gre');
1686

    
1687
	/* set up GIF virtual interfaces */
1688
	interfaces_tunnel_configure(1,'','gif');
1689

    
1690
	/* set up BRIDGE virtual interfaces */
1691
	interfaces_bridge_configure(1);
1692

    
1693
	foreach ($track6_list as $if => $ifname) {
1694
		if (is_platform_booting()) {
1695
			printf(gettext("Configuring %s interface..."), $ifname);
1696
		}
1697
		if (g_get('debug')) {
1698
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1699
		}
1700

    
1701
		interface_configure($if, $reload);
1702

    
1703
		if (is_platform_booting()) {
1704
			echo gettext("done.") . "\n";
1705
		}
1706
	}
1707

    
1708
	/* bring up vip interfaces */
1709
	interfaces_vips_configure();
1710

    
1711
	/* set up GRE virtual interfaces */
1712
	interfaces_tunnel_configure(2,'','gre');
1713

    
1714
	/* set up GIF virtual interfaces */
1715
	interfaces_tunnel_configure(2,'','gif');
1716

    
1717
	foreach ($delayed_list as $if => $ifname) {
1718
		if (is_platform_booting()) {
1719
			printf(gettext("Configuring %s interface..."), $ifname);
1720
		}
1721
		if (g_get('debug')) {
1722
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1723
		}
1724

    
1725
		interface_configure($if, $reload);
1726

    
1727
		if (is_platform_booting()) {
1728
			echo gettext("done.") . "\n";
1729
		}
1730
	}
1731

    
1732
	/* set up BRIDGE virtual interfaces */
1733
	interfaces_bridge_configure(2);
1734

    
1735
	foreach ($bridge_list as $if => $ifname) {
1736
		if (is_platform_booting()) {
1737
			printf(gettext("Configuring %s interface..."), $ifname);
1738
		}
1739
		if (g_get('debug')) {
1740
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1741
		}
1742

    
1743
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1744
		// redmine #3997
1745
		interface_reconfigure($if, $reload);
1746
		interfaces_vips_configure($if);
1747

    
1748
		if (is_platform_booting()) {
1749
			echo gettext("done.") . "\n";
1750
		}
1751
	}
1752

    
1753
	foreach ($dhcp6c_list as $if => $ifname) {
1754
		if (is_platform_booting()) {
1755
			printf(gettext("Configuring %s interface..."), $ifname);
1756
		}
1757
		if (g_get('debug')) {
1758
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1759
		}
1760

    
1761
		interface_configure($if, $reload);
1762

    
1763
		if (is_platform_booting()) {
1764
			echo gettext("done.") . "\n";
1765
		}
1766
	}
1767

    
1768
	/* set up IPsec VTI interfaces */
1769
	interfaces_ipsec_vti_configure();
1770

    
1771
	/* configure interface groups */
1772
	interfaces_group_setup();
1773

    
1774
	if (!is_platform_booting()) {
1775
		/* reconfigure static routes (kernel may have deleted them) */
1776
		system_routing_configure();
1777

    
1778
		/* reload IPsec tunnels */
1779
		ipsec_configure();
1780

    
1781
		/* restart dns servers (defering dhcpd reload) */
1782
		if (config_get_path('dnsmasq/enable')) {
1783
			services_dnsmasq_configure(false);
1784
		}
1785
		if (config_get_path('unbound/enable')) {
1786
			services_unbound_configure(false);
1787
		}
1788

    
1789
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1790
		services_dhcpd_configure();
1791
	}
1792

    
1793
	return 0;
1794
}
1795

    
1796
function interface_reconfigure($interface = "wan", $reloadall = false) {
1797
	interface_bring_down($interface);
1798
	interface_configure($interface, $reloadall);
1799
}
1800

    
1801
function interface_vip_bring_down($vip) {
1802
	global $g;
1803

    
1804
	$vipif = get_real_interface($vip['interface']);
1805
	switch ($vip['mode']) {
1806
		case "proxyarp":
1807
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1808
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1809
			}
1810
			break;
1811
		case "ipalias":
1812
			if (does_interface_exist($vipif)) {
1813
				if (is_ipaddrv6($vip['subnet'])) {
1814
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1815
				} else {
1816
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1817
				}
1818
			}
1819
			break;
1820
		case "carp":
1821
			/* XXX: Is enough to delete ip address? */
1822
			if (does_interface_exist($vipif)) {
1823
				if (is_ipaddrv6($vip['subnet'])) {
1824
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1825
				} else {
1826
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1827
				}
1828
			}
1829
			break;
1830
	}
1831
}
1832

    
1833
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1834
	global $g;
1835

    
1836
	$iface = config_get_path("interfaces/{$interface}");
1837
	if (!$iface) {
1838
		return;
1839
	}
1840

    
1841
	if (g_get('debug')) {
1842
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1843
	}
1844

    
1845
	/*
1846
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1847
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1848
	 * Keep this in mind while doing changes here!
1849
	 */
1850
	if ($ifacecfg === false) {
1851
		$ifcfg = $iface;
1852
		$ppps = config_get_path('ppps/ppp', []);
1853
		$realif = get_real_interface($interface);
1854
		$realifv6 = get_real_interface($interface, "inet6", true);
1855
	} elseif (!is_array($ifacecfg)) {
1856
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1857
		$ifcfg = $iface;
1858
		$ppps = config_get_path('ppps/ppp', []);
1859
		$realif = get_real_interface($interface);
1860
		$realifv6 = get_real_interface($interface, "inet6", true);
1861
	} else {
1862
		$ifcfg = $ifacecfg['ifcfg'];
1863
		$ppps = $ifacecfg['ppps'];
1864
		if (isset($ifacecfg['ifcfg']['realif'])) {
1865
			$realif = $ifacecfg['ifcfg']['realif'];
1866
			/* XXX: Any better way? */
1867
			$realifv6 = $realif;
1868
		} else {
1869
			$realif = get_real_interface($interface);
1870
			$realifv6 = get_real_interface($interface, "inet6", true);
1871
		}
1872
	}
1873

    
1874
	/* check all gateways, including dynamic,
1875
	 * see https://redmine.pfsense.org/issues/12920 */
1876
	foreach (get_gateways(GW_CACHE_DISABLED) as $gw) {
1877
		if ($gw['friendlyiface'] == $interface) {
1878
			$restart_gateways_monitor = true;
1879
			break;
1880
		}
1881
	}
1882

    
1883
	switch ($ifcfg['ipaddr']) {
1884
		case "ppp":
1885
		case "pppoe":
1886
		case "pptp":
1887
		case "l2tp":
1888
			if (is_array($ppps) && count($ppps)) {
1889
				foreach ($ppps as  $ppp) {
1890
					if ($realif == $ppp['if']) {
1891
						if (isset($ppp['ondemand']) && !$destroy) {
1892
							send_event("interface reconfigure {$interface}");
1893
							break;
1894
						}
1895
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1896
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1897
							sleep(2);
1898
						}
1899
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1900
						break;
1901
					}
1902
				}
1903
			}
1904
			break;
1905
		case "dhcp":
1906
			kill_dhclient_process($realif);
1907
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1908
			if (does_interface_exist("$realif")) {
1909
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1910
				interface_vip_cleanup($interface, "inet4");
1911
				if ($destroy == true) {
1912
					pfSense_interface_flags($realif, -IFF_UP);
1913
				}
1914
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1915
			}
1916
			break;
1917
		default:
1918
			if (does_interface_exist("$realif")) {
1919
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1920
				interface_vip_cleanup($interface, "inet4");
1921
				if ($destroy == true) {
1922
					pfSense_interface_flags($realif, -IFF_UP);
1923
				}
1924
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1925
			}
1926
			break;
1927
	}
1928

    
1929
	$track6 = array();
1930
	switch ($ifcfg['ipaddrv6']) {
1931
		case "slaac":
1932
		case "dhcp6":
1933
			interface_dhcpv6_configure($interface, $ifcfg, true);
1934
			if (does_interface_exist($realifv6)) {
1935
				mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 -accept_rtadv");
1936
				$ip6 = find_interface_ipv6($realifv6);
1937
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1938
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1939
				}
1940
				interface_vip_cleanup($interface, "inet6");
1941
				if ($destroy == true) {
1942
					pfSense_interface_flags($realif, -IFF_UP);
1943
				}
1944
			}
1945
			$track6 = link_interface_to_track6($interface);
1946
			break;
1947
		case "6rd":
1948
		case "6to4":
1949
			$realif = "{$interface}_stf";
1950
			if (does_interface_exist("$realif")) {
1951
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1952
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($iface['ipaddrv6']) || $iface['ipaddrv6'] != '6rd')) ||
1953
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($iface['ipaddrv6']) || $iface['ipaddrv6'] != '6to4'))) {
1954
					$destroy = true;
1955
				} else {
1956
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1957
					$ip6 = get_interface_ipv6($interface);
1958
					if (is_ipaddrv6($ip6)) {
1959
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1960
					}
1961
				}
1962
				interface_vip_cleanup($interface, "inet6");
1963
				if ($destroy == true) {
1964
					pfSense_interface_flags($realif, -IFF_UP);
1965
				}
1966
			}
1967
			$track6 = link_interface_to_track6($interface);
1968
			break;
1969
		default:
1970
			if (does_interface_exist("$realif")) {
1971
				$ip6 = get_interface_ipv6($interface);
1972
				if (is_ipaddrv6($ip6)) {
1973
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
1974
				}
1975
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
1976
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
1977
				}
1978
				interface_vip_cleanup($interface, "inet6");
1979
				if ($destroy == true) {
1980
					pfSense_interface_flags($realif, -IFF_UP);
1981
				}
1982
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1983
			}
1984
			$track6 = link_interface_to_track6($interface);
1985
			break;
1986
	}
1987

    
1988
	if (!empty($track6) && is_array($track6)) {
1989
		if (!function_exists('services_dhcpd_configure')) {
1990
			require_once('services.inc');
1991
		}
1992
		/* Bring down radvd and dhcp6 on these interfaces */
1993
		services_dhcpd_configure('inet6');
1994
	}
1995

    
1996
	/* remove interface up file if it exists */
1997
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
1998
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
1999
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
2000
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
2001
		rename("{$g['tmp_path']}/{$realif}_router", "{$g['tmp_path']}/{$realif}_router.last");
2002
	}
2003
	if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
2004
		rename("{$g['tmp_path']}/{$realif}_routerv6", "{$g['tmp_path']}/{$realif}_routerv6.last");
2005
	}
2006
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
2007
	unlink_if_exists("{$g['varetc_path']}/nameserver_v6{$interface}");
2008
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
2009
	unlink_if_exists("{$g['varetc_path']}/searchdomain_v6{$interface}");
2010
	unlink_if_exists("{$g['tmp_path']}/{$interface}_upstart4");
2011
	unlink_if_exists("{$g['tmp_path']}/{$interface}_upstart6");
2012

    
2013
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
2014
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
2015
	if (is_array($ifcfg['wireless'])) {
2016
		kill_hostapd($realif);
2017
		mwexec(kill_wpasupplicant($realif));
2018
		unlink_if_exists("{$g['varetc_path']}/wpa_supplicant_{$realif}.*");
2019
		unlink_if_exists("{$g['varetc_path']}/hostapd_{$realif}.conf");
2020
	}
2021

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

    
2026
			/* Invalidate cache */
2027
			get_interface_arr(true);
2028
		}
2029
	}
2030

    
2031
	/* If interface has a gateway, we need to bounce dpinger to keep dpinger happy */
2032
	if ($restart_gateways_monitor) {
2033
		setup_gateways_monitor();
2034
	}
2035

    
2036
	return;
2037
}
2038

    
2039
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
2040
	if (config_path_enabled('/','virtualip_carp_maintenancemode') && ($carp_maintenancemode == false)) {
2041
		config_del_path('virtualip_carp_maintenancemode');
2042
		write_config("Leave CARP maintenance mode");
2043
	} elseif (!config_path_enabled('/','virtualip_carp_maintenancemode') && ($carp_maintenancemode == true)) {
2044
		config_set_path('virtualip_carp_maintenancemode', true);
2045
		write_config(gettext("Enter CARP maintenance mode"));
2046
	}
2047
	config_init_path('virtualip/vip');
2048

    
2049
	foreach (config_get_path('virtualip/vip', []) as $vip) {
2050
		if ($vip['mode'] == "carp") {
2051
			interface_carp_configure($vip, true);
2052
		}
2053
	}
2054
}
2055

    
2056
function interface_wait_tentative($interface, $timeout = 10) {
2057
	if (!does_interface_exist($interface)) {
2058
		return false;
2059
	}
2060

    
2061
	$time = 0;
2062
	while ($time <= $timeout) {
2063
		$if = get_interface_addresses($interface);
2064
		if (!isset($if['tentative'])) {
2065
			return true;
2066
		}
2067
		sleep(1);
2068
		$time++;
2069
	}
2070

    
2071
	return false;
2072
}
2073

    
2074
function interface_isppp_type($interface) {
2075
	$iface = config_get_path("interfaces/{$interface}");
2076
	if (!is_array($iface)) {
2077
		return false;
2078
	}
2079

    
2080
	switch ($iface['ipaddr']) {
2081
		case 'pptp':
2082
		case 'l2tp':
2083
		case 'pppoe':
2084
		case 'ppp':
2085
			return true;
2086
			break;
2087
		default:
2088
			return false;
2089
			break;
2090
	}
2091
}
2092

    
2093
function interfaces_ptpid_used($ptpid) {
2094
	$ppps = config_get_path('ppps/ppp');
2095
	if (is_array($ppps)) {
2096
		foreach ($ppps as $settings) {
2097
			if ($ptpid == $settings['ptpid']) {
2098
				return true;
2099
			}
2100
		}
2101
	}
2102

    
2103
	return false;
2104
}
2105

    
2106
function interfaces_ptpid_next() {
2107
	$ptpid = 0;
2108
	while (interfaces_ptpid_used($ptpid)) {
2109
		$ptpid++;
2110
	}
2111

    
2112
	return $ptpid;
2113
}
2114

    
2115
function getMPDCRONSettings($pppif) {
2116
	global $g;
2117

    
2118
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2119
	foreach (config_get_path('cron/item', []) as $i => $item) {
2120
		if (stripos($item['command'], $cron_cmd_file) !== false) {
2121
			return array("ID" => $i, "ITEM" => $item);
2122
		}
2123
	}
2124

    
2125
	return NULL;
2126
}
2127

    
2128
function handle_pppoe_reset($post_array) {
2129
	global $g;
2130

    
2131
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2132
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2133

    
2134
	if (!is_array(config_get_path('cron/item'))) {
2135
		if (config_set_path('cron/item', array()) === null)
2136
			log_error(gettext('Cron section in config root is invalid.'));
2137
			return;
2138
	}
2139

    
2140
	$itemhash = getMPDCRONSettings($pppif);
2141

    
2142
	// reset cron items if necessary and return
2143
	if (empty($post_array['pppoe-reset-type'])) {
2144
		if (isset($itemhash)) {
2145
			config_del_path("cron/item/{$itemhash['ID']}");
2146
		}
2147
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2148
		return;
2149
	}
2150

    
2151
	if (empty($itemhash)) {
2152
		$itemhash = array();
2153
	}
2154
	$item = array();
2155
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
2156
		$item['minute'] = (strlen($post_array['pppoe_resetminute']) > 0) ? $post_array['pppoe_resetminute'] : "*";
2157
		$item['hour'] = (strlen($post_array['pppoe_resethour']) > 0) ? $post_array['pppoe_resethour'] : "*";
2158
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
2159
			$date = explode("/", $post_array['pppoe_resetdate']);
2160
			$item['mday'] = $date[1];
2161
			$item['month'] = $date[0];
2162
		} else {
2163
			$item['mday'] = "*";
2164
			$item['month'] = "*";
2165
		}
2166
		$item['wday'] = "*";
2167
		$item['who'] = "root";
2168
		$item['command'] = $cron_cmd_file;
2169
	} elseif (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
2170
		switch ($post_array['pppoe_pr_preset_val']) {
2171
			case "monthly":
2172
				$item['minute'] = "0";
2173
				$item['hour'] = "0";
2174
				$item['mday'] = "1";
2175
				$item['month'] = "*";
2176
				$item['wday'] = "*";
2177
				break;
2178
			case "weekly":
2179
				$item['minute'] = "0";
2180
				$item['hour'] = "0";
2181
				$item['mday'] = "*";
2182
				$item['month'] = "*";
2183
				$item['wday'] = "0";
2184
				break;
2185
			case "daily":
2186
				$item['minute'] = "0";
2187
				$item['hour'] = "0";
2188
				$item['mday'] = "*";
2189
				$item['month'] = "*";
2190
				$item['wday'] = "*";
2191
				break;
2192
			case "hourly":
2193
				$item['minute'] = "0";
2194
				$item['hour'] = "*";
2195
				$item['mday'] = "*";
2196
				$item['month'] = "*";
2197
				$item['wday'] = "*";
2198
				break;
2199
		} // end switch
2200
		$item['who'] = "root";
2201
		$item['command'] = $cron_cmd_file;
2202
	}
2203
	if (empty($item)) {
2204
		return;
2205
	}
2206
	if (isset($itemhash['ID'])) {
2207
		config_set_path("cron/item/{$itemhash['ID']}", $item);
2208
	} else {
2209
		config_set_path('cron/item/', $item);
2210
	}
2211
}
2212

    
2213
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2214
	$ppp_list = array();
2215
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
2216
		$ports = explode(",", $ppp['ports']);
2217
		foreach($ports as $port) {
2218
			foreach($triggerinterfaces as $vip) {
2219
				if ($port == "_vip{$vip['uniqid']}") {
2220
					$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2221
					$ppp_list[$if] = 1;
2222
				}
2223
			}
2224
		}
2225
	}
2226
	foreach(array_keys($ppp_list) as $pppif) {
2227
		interface_ppps_configure($pppif);
2228
	}
2229
}
2230

    
2231
/*
2232
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2233
 * It writes the mpd config file to /var/etc every time the link is opened.
2234
 */
2235
function interface_ppps_configure($interface) {
2236
	global $g;
2237

    
2238
	$iface = config_get_path("interfaces/{$interface}");
2239
	/* Return for unassigned interfaces. This is a minimum requirement. */
2240
	if (empty($iface)) {
2241
		return 0;
2242
	}
2243
	$ifcfg = $iface;
2244
	if (!isset($ifcfg['enable'])) {
2245
		return 0;
2246
	}
2247

    
2248
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2249
	if (!is_dir("/var/spool/lock")) {
2250
		mkdir("/var/spool/lock", 0777, true);
2251
	}
2252
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2253
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2254
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2255
	}
2256

    
2257
	$pppid = "";
2258
	$ppp = array();
2259
	$ppps = config_get_path('ppps/ppp');
2260
	if (is_array($ppps) && count($ppps)) {
2261
		foreach ($ppps as $pppid => $ppp) {
2262
			if ($ifcfg['if'] == $ppp['if']) {
2263
				break;
2264
			}
2265
		}
2266
	}
2267
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2268
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2269
		return 0;
2270
	}
2271
	$pppif = $ifcfg['if'];
2272
	if ($ppp['type'] == "ppp") {
2273
		$type = "modem";
2274
	} else {
2275
		$type = $ppp['type'];
2276
	}
2277

    
2278
	$confports = explode(',', $ppp['ports']);
2279
	if ($type == "modem") {
2280
		$ports = $confports;
2281
	} else {
2282
		$ports = array();
2283
		foreach ($confports as $pid => $port) {
2284
			if (strstr($port, "_vip")) {
2285
				if (get_carp_interface_status($port) != "MASTER") {
2286
					continue;
2287
				}
2288
			}
2289
			$ports[$pid] = get_real_interface($port);
2290
			if (empty($ports[$pid])) {
2291
				return 0;
2292
			}
2293
		}
2294
	}
2295
	$localips = explode(',', $ppp['localip']);
2296
	$gateways = explode(',', $ppp['gateway']);
2297
	$subnets = explode(',', $ppp['subnet']);
2298

    
2299
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2300
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2301
	 */
2302
	foreach ($ports as $pid => $port) {
2303
		switch ($ppp['type']) {
2304
			case "pppoe":
2305
				/* Bring the parent interface up */
2306
				interfaces_bring_up($port);
2307
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2308
				$ngif = str_replace(".", "_", $port);
2309
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2310
				break;
2311
			case "pptp":
2312
			case "l2tp":
2313
				/* configure interface */
2314
				if (is_ipaddr($localips[$pid])) {
2315
					// Manually configure interface IP/subnet
2316
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2317
					interfaces_bring_up($port);
2318
				} elseif (empty($localips[$pid])) {
2319
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2320
				}
2321

    
2322
				if (!is_ipaddr($localips[$pid])) {
2323
					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));
2324
					$localips[$pid] = "0.0.0.0";
2325
				}
2326
				if (!g_get('booting') && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2327
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2328
				}
2329
				if (!is_ipaddr($gateways[$pid])) {
2330
					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']));
2331
					return 0;
2332
				}
2333
				break;
2334
			case "ppp":
2335
				if (!file_exists("{$port}")) {
2336
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2337
					return 0;
2338
				}
2339
				break;
2340
			default:
2341
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2342
				break;
2343
		}
2344
	}
2345

    
2346
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2347
	    (is_array($ports) && count($ports) > 1)) {
2348
		$multilink = "enable";
2349
	} else {
2350
		$multilink = "disable";
2351
	}
2352

    
2353
	if ($type == "modem") {
2354
		if (is_ipaddr($ppp['localip'])) {
2355
			$localip = $ppp['localip'];
2356
		} else {
2357
			$localip = '0.0.0.0';
2358
		}
2359

    
2360
		if (is_ipaddr($ppp['gateway'])) {
2361
			$gateway = $ppp['gateway'];
2362
		} else {
2363
			$gateway = "10.64.64.{$pppid}";
2364
		}
2365
		$ranges = "{$localip}/0 {$gateway}/0";
2366

    
2367
		if (empty($ppp['apnum'])) {
2368
			$ppp['apnum'] = 1;
2369
		}
2370
	} else {
2371
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2372
	}
2373

    
2374
	if (isset($ppp['ondemand'])) {
2375
		$ondemand = "enable";
2376
	} else {
2377
		$ondemand = "disable";
2378
	}
2379
	if (!isset($ppp['idletimeout'])) {
2380
		$ppp['idletimeout'] = 0;
2381
	}
2382

    
2383
	if (empty($ppp['username']) && $type == "modem") {
2384
		$ppp['username'] = "user";
2385
		$ppp['password'] = "none";
2386
	}
2387
	if (empty($ppp['password']) && $type == "modem") {
2388
		$passwd = "none";
2389
	} else {
2390
		$passwd = base64_decode($ppp['password']);
2391
	}
2392

    
2393
	$bandwidths = explode(',', $ppp['bandwidth']);
2394
	$defaultmtu = "1492";
2395
	if (!empty($ifcfg['mtu'])) {
2396
		$defaultmtu = intval($ifcfg['mtu']);
2397
	}
2398
	if (isset($ppp['mtu'])) {
2399
		$mtus = explode(',', $ppp['mtu']);
2400
	}
2401
	if (isset($ppp['mru'])) {
2402
		$mrus = explode(',', $ppp['mru']);
2403
	}
2404
	if (isset($ppp['mrru'])) {
2405
		$mrrus = explode(',', $ppp['mrru']);
2406
	}
2407
	if (!empty($ifcfg['ipaddrv6'])) {
2408
		$ipv6cp = "set bundle enable ipv6cp";
2409
	}
2410

    
2411
	// Construct the mpd.conf file
2412
	$mpdconf = <<<EOD
2413
startup:
2414
	# configure the console
2415
	set console close
2416
	# configure the web server
2417
	set web close
2418

    
2419
default:
2420
{$ppp['type']}client:
2421
	create bundle static {$interface}
2422
	set bundle period 6
2423
	set bundle lowat 0
2424
	set bundle hiwat 0
2425
	set bundle min-con 3
2426
	set bundle min-dis 6
2427
	set bundle enable bw-manage
2428
	{$ipv6cp}
2429
	set iface name {$pppif}
2430

    
2431
EOD;
2432

    
2433
	if (isset($ifcfg['descr'])) {
2434
		$mpdconf .= <<<EOD
2435
	set iface description "{$ifcfg['descr']}"
2436

    
2437
EOD;
2438
	}
2439
	$setdefaultgw = false;
2440
	$defgw4 = lookup_gateway_or_group_by_name(config_get_path('gateways/defaultgw4'));
2441
//	$defgw6 = lookup_gateway_or_group_by_name(config_get_path('gateways/defaultgw6'));
2442
	if ($defgw4['interface'] == $interface) {
2443
		$setdefaultgw = true;
2444
	}
2445

    
2446
/* Omit this, we maintain the default route by other means, and it causes problems with
2447
 * default gateway switching. See redmine #1837 for original issue
2448
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2449
 * edge case. redmine #6495 open to address.
2450
 */
2451
	if ($setdefaultgw == true) {
2452
		$mpdconf .= <<<EOD
2453
	set iface route default
2454

    
2455
EOD;
2456
	}
2457

    
2458
	$mpdconf .= <<<EOD
2459
	set iface {$ondemand} on-demand
2460
	set iface idle {$ppp['idletimeout']}
2461

    
2462
EOD;
2463

    
2464
	if (isset($ppp['ondemand'])) {
2465
		$mpdconf .= <<<EOD
2466
	set iface addrs 10.10.1.1 10.10.1.2
2467

    
2468
EOD;
2469
	}
2470

    
2471
	if (isset($ppp['mtu-override']) &&
2472
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2473
		/* Find the smaller MTU set on ports */
2474
		$mtu = $defaultmtu;
2475
		foreach ($ports as $pid => $port) {
2476
			if (empty($mtus[$pid])) {
2477
				$mtus[$pid] = $defaultmtu;
2478
			}
2479
			if ($type == "pppoe") {
2480
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2481
					$mtus[$pid] = get_interface_mtu($port) - 8;
2482
				}
2483
			}
2484
			if ($mtu > $mtus[$pid]) {
2485
				$mtu = $mtus[$pid];
2486
			}
2487
		}
2488
		$mpdconf .= <<<EOD
2489
	set iface mtu {$mtu} override
2490

    
2491
EOD;
2492
	}
2493

    
2494
	if (isset($ppp['tcpmssfix'])) {
2495
		$tcpmss = "disable";
2496
	} else {
2497
		$tcpmss = "enable";
2498
	}
2499
	$mpdconf .= <<<EOD
2500
	set iface {$tcpmss} tcpmssfix
2501

    
2502
EOD;
2503

    
2504
	$mpdconf .= <<<EOD
2505
	set iface up-script /usr/local/sbin/ppp-linkup
2506
	set iface down-script /usr/local/sbin/ppp-linkdown
2507
	set ipcp ranges {$ranges}
2508

    
2509
EOD;
2510
	if (isset($ppp['vjcomp'])) {
2511
		$mpdconf .= <<<EOD
2512
	set ipcp no vjcomp
2513

    
2514
EOD;
2515
	}
2516

    
2517
	if (config_path_enabled('system', 'dnsallowoverride')) {
2518
		$mpdconf .= <<<EOD
2519
	set ipcp enable req-pri-dns
2520
	set ipcp enable req-sec-dns
2521

    
2522
EOD;
2523
	}
2524

    
2525
	if (!isset($ppp['verbose_log'])) {
2526
		$mpdconf .= <<<EOD
2527
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2528

    
2529
EOD;
2530
	}
2531

    
2532
	foreach ($ports as $pid => $port) {
2533
		$port = get_real_interface($port);
2534
		$mpdconf .= <<<EOD
2535

    
2536
	create link static {$interface}_link{$pid} {$type}
2537
	set link action bundle {$interface}
2538
	set link {$multilink} multilink
2539
	set link keep-alive 10 60
2540
	set link max-redial 0
2541

    
2542
EOD;
2543
		if (isset($ppp['shortseq'])) {
2544
			$mpdconf .= <<<EOD
2545
	set link no shortseq
2546

    
2547
EOD;
2548
		}
2549

    
2550
		if (isset($ppp['acfcomp'])) {
2551
			$mpdconf .= <<<EOD
2552
	set link no acfcomp
2553

    
2554
EOD;
2555
		}
2556

    
2557
		if (isset($ppp['protocomp'])) {
2558
			$mpdconf .= <<<EOD
2559
	set link no protocomp
2560

    
2561
EOD;
2562
		}
2563

    
2564
		$mpdconf .= <<<EOD
2565
	set link disable chap pap
2566
	set link accept chap pap eap
2567
	set link disable incoming
2568

    
2569
EOD;
2570

    
2571

    
2572
		if (!empty($bandwidths[$pid])) {
2573
			$mpdconf .= <<<EOD
2574
	set link bandwidth {$bandwidths[$pid]}
2575

    
2576
EOD;
2577
		}
2578

    
2579
		if (empty($mtus[$pid])) {
2580
			$mtus[$pid] = $defaultmtu;
2581
		}
2582
		if ($type == "pppoe") {
2583
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2584
				$mtus[$pid] = get_interface_mtu($port) - 8;
2585
			}
2586
		}
2587
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2588
		    !isset($ppp['mtu-override']) &&
2589
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2590
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2591
			$mpdconf .= <<<EOD
2592
	set link mtu {$mtus[$pid]}
2593

    
2594
EOD;
2595
		}
2596

    
2597
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2598
		    !isset($ppp['mtu-override']) &&
2599
		    !empty($mrus[$pid])) {
2600
			$mpdconf .= <<<EOD
2601
	set link mru {$mrus[$pid]}
2602

    
2603
EOD;
2604
		}
2605

    
2606
		if (!empty($mrrus[$pid])) {
2607
			$mpdconf .= <<<EOD
2608
	set link mrru {$mrrus[$pid]}
2609

    
2610
EOD;
2611
		}
2612

    
2613
		$mpdconf .= <<<EOD
2614
	set auth authname "{$ppp['username']}"
2615
	set auth password {$passwd}
2616

    
2617
EOD;
2618
		if ($type == "modem") {
2619
			$mpdconf .= <<<EOD
2620
	set modem device {$ppp['ports']}
2621
	set modem script DialPeer
2622
	set modem idle-script Ringback
2623
	set modem watch -cd
2624
	set modem var \$DialPrefix "DT"
2625
	set modem var \$Telephone "{$ppp['phone']}"
2626

    
2627
EOD;
2628
		}
2629
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2630
			$mpdconf .= <<<EOD
2631
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2632

    
2633
EOD;
2634
		}
2635
		if (isset($ppp['initstr']) && $type == "modem") {
2636
			$initstr = base64_decode($ppp['initstr']);
2637
			$mpdconf .= <<<EOD
2638
	set modem var \$InitString "{$initstr}"
2639

    
2640
EOD;
2641
		}
2642
		if (isset($ppp['simpin']) && $type == "modem") {
2643
			if ($ppp['pin-wait'] == "") {
2644
				$ppp['pin-wait'] = 0;
2645
			}
2646
			$mpdconf .= <<<EOD
2647
	set modem var \$SimPin "{$ppp['simpin']}"
2648
	set modem var \$PinWait "{$ppp['pin-wait']}"
2649

    
2650
EOD;
2651
		}
2652
		if (isset($ppp['apn']) && $type == "modem") {
2653
			$mpdconf .= <<<EOD
2654
	set modem var \$APN "{$ppp['apn']}"
2655
	set modem var \$APNum "{$ppp['apnum']}"
2656

    
2657
EOD;
2658
		}
2659
		if ($type == "pppoe") {
2660
			$hostuniq = '';
2661
			if (!empty($ppp['hostuniq'])) {
2662
				if (preg_match('/^0x[a-fA-F0-9]+$/', $ppp['hostuniq'])) {
2663
					$hostuniq = strtolower($ppp['hostuniq']) .'|';
2664
				} elseif (preg_match('/^[a-zA-Z0-9]+$/i', $ppp['hostuniq'])) {
2665
					$hostuniq = '0x' . bin2hex($ppp['hostuniq']) . '|';
2666
				}
2667
			}
2668
			// Send a null service name if none is set.
2669
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2670
			$mpdconf .= <<<EOD
2671
	set pppoe service "{$hostuniq}{$provider}"
2672

    
2673
EOD;
2674
		}
2675
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2676
			$mpdconf .= <<<EOD
2677
	set pppoe max-payload {$mtus[$pid]}
2678

    
2679
EOD;
2680
		}
2681
		if ($type == "pppoe") {
2682
			$mpdconf .= <<<EOD
2683
	set pppoe iface {$port}
2684

    
2685
EOD;
2686
		}
2687

    
2688
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2689
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2690
			$mpdconf .= <<<EOD
2691
	set l2tp secret "{$secret}"
2692

    
2693
EOD;
2694
		}
2695

    
2696
		if (($type == "pptp") || ($type == "l2tp")) {
2697
			$mpdconf .= <<<EOD
2698
	set {$type} self {$localips[$pid]}
2699
	set {$type} peer {$gateways[$pid]}
2700

    
2701
EOD;
2702
		}
2703

    
2704
		$mpdconf .= "\topen\n";
2705
	} //end foreach ($port)
2706

    
2707

    
2708
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2709
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2710
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2711
	} else {
2712
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2713
		if (!$fd) {
2714
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2715
			return 0;
2716
		}
2717
		// Write out mpd_ppp.conf
2718
		fwrite($fd, $mpdconf);
2719
		fclose($fd);
2720
		unset($mpdconf);
2721
	}
2722

    
2723
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2724
	if (isset($ppp['uptime'])) {
2725
		if (!file_exists("/conf/{$pppif}.log")) {
2726
			file_put_contents("/conf/{$pppif}.log", '');
2727
		}
2728
	} else {
2729
		if (file_exists("/conf/{$pppif}.log")) {
2730
			@unlink("/conf/{$pppif}.log");
2731
		}
2732
	}
2733

    
2734
	/* clean up old lock files */
2735
	foreach ($ports as $port) {
2736
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2737
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2738
		}
2739
	}
2740

    
2741
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2742
	/* random IPv6 interface identifier during boot. More details at */
2743
	/* https://forum.netgate.com/post/592474 */
2744
	if (is_platform_booting()) {
2745
		$count = 0;
2746
		foreach (config_get_path('interfaces', []) as $tempifacename => $tempiface) {
2747
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2748
				$tempaddr[$count]['if'] = $tempiface['if'];
2749
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2750
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2751
				$count++;
2752
			}
2753
			// Maximum /31 is is x.y.z.254/31
2754
			if ($count > 122) {
2755
				break;
2756
			}
2757
		}
2758
		unset($count);
2759
	}
2760

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

    
2766
	// Check for PPPoE periodic reset request
2767
	if ($type == "pppoe") {
2768
		if (!empty($ppp['pppoe-reset-type'])) {
2769
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2770
		} else {
2771
			interface_setup_pppoe_reset_file($ppp['if']);
2772
		}
2773
	}
2774
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2775
	$i = 0;
2776
	while ($i < 10) {
2777
		if (does_interface_exist($ppp['if'], true)) {
2778
			break;
2779
		}
2780
		sleep(3);
2781
		$i++;
2782
	}
2783

    
2784
	/* Remove all temporary bogon IPv4 addresses */
2785
	if (is_array($tempaddr)) {
2786
		foreach ($tempaddr as $tempiface) {
2787
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2788
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2789
			}
2790
		}
2791
		unset ($tempaddr);
2792
	}
2793

    
2794
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2795
	/* We should be able to launch the right version for each modem */
2796
	/* We can also guess the mondev from the manufacturer */
2797
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2798
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2799
	foreach ($ports as $port) {
2800
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2801
			$mondev = substr(basename($port), 0, -1);
2802
			$devlist = glob("/dev/{$mondev}?");
2803
			$mondev = basename(end($devlist));
2804
		}
2805
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2806
			$mondev = substr(basename($port), 0, -1) . "1";
2807
		}
2808
		if ($mondev != '') {
2809
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2810
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2811
		}
2812
	}
2813

    
2814
	return 1;
2815
}
2816

    
2817
function interfaces_sync_setup() {
2818

    
2819
	if (config_get_path('system/developerspew')) {
2820
		$mt = microtime();
2821
		echo "interfaces_sync_setup() being called $mt\n";
2822
	}
2823

    
2824
	if (is_platform_booting()) {
2825
		echo gettext("Configuring CARP settings...");
2826
		mute_kernel_msgs();
2827
	}
2828

    
2829
	/* suck in configuration items */
2830
	if (!empty(config_get_path('hasync'))) {
2831
		$pfsyncenabled = config_get_path('hasync/pfsyncenabled');
2832
		$pfsyncinterface = config_get_path('hasync/pfsyncinterface');
2833
		$pfsyncpeerip = config_get_path('hasync/pfsyncpeerip');
2834
	}
2835

    
2836
	set_sysctl(array(
2837
		"net.inet.carp.preempt" => "1",
2838
		"net.inet.carp.log" => "1")
2839
	);
2840

    
2841
	if (!empty($pfsyncinterface)) {
2842
		$carp_sync_int = get_real_interface($pfsyncinterface);
2843
	}
2844

    
2845
	/* setup pfsync interface */
2846
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2847
		if (is_ipaddr($pfsyncpeerip)) {
2848
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2849
		} else {
2850
			$syncpeer = "-syncpeer";
2851
		}
2852

    
2853
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} " .
2854
		    "{$syncpeer} up");
2855
		mwexec("/sbin/ifconfig pfsync0 -defer");
2856

    
2857
		/*
2858
		 * XXX: Handle an issue with pfsync(4) and carp(4). In a
2859
		 * cluster carp will come up before pfsync(4) has updated and
2860
		 * so will cause issues for existing sessions.
2861
		 */
2862
		log_error(gettext("waiting for pfsync..."));
2863

    
2864
		$i = 0;
2865
		do {
2866
			sleep(1);
2867
			exec('/sbin/ifconfig pfsync0 | ' .
2868
				 '/usr/bin/grep -q "syncok: 0" 2>/dev/null', $output,
2869
				 $rc);
2870
			$i++;
2871
		} while ($rc != 0 && $i <= 30);
2872

    
2873
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2874
		log_error(gettext("Configuring CARP settings finalize..."));
2875
	} else {
2876
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down");
2877
	}
2878

    
2879
	/* Don't enable CARP if we haven't booted */
2880
	if (!is_platform_booting()) {
2881
		enable_carp();
2882
	}
2883

    
2884
	if (is_platform_booting()) {
2885
		unmute_kernel_msgs();
2886
		echo gettext("done.") . "\n";
2887
	}
2888
}
2889

    
2890
function interface_proxyarp_configure($interface = "") {
2891
	global $g;
2892
	if (config_get_path('system/developerspew')) {
2893
		$mt = microtime();
2894
		echo "interface_proxyarp_configure() being called $mt\n";
2895
	}
2896

    
2897
	/* kill any running choparp */
2898
	if (empty($interface)) {
2899
		killbyname("choparp");
2900
	} else {
2901
		$vipif = get_real_interface($interface);
2902
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2903
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2904
		}
2905
	}
2906

    
2907
	$paa = array();
2908
	$vips = config_get_path('virtualip/vip');
2909
	if (is_array($vips)) {
2910

    
2911
		/* group by interface */
2912
		foreach ($vips as $vipent) {
2913
			if ($vipent['mode'] === "proxyarp") {
2914
				if ($vipent['interface']) {
2915
					$proxyif = $vipent['interface'];
2916
				} else {
2917
					$proxyif = "wan";
2918
				}
2919

    
2920
				if (!empty($interface) && $interface != $proxyif) {
2921
					continue;
2922
				}
2923

    
2924
				if (!is_array($paa[$proxyif])) {
2925
					$paa[$proxyif] = array();
2926
				}
2927

    
2928
				$paa[$proxyif][] = $vipent;
2929
			}
2930
		}
2931
	}
2932

    
2933
	if (!empty($interface)) {
2934
		if (is_array($paa[$interface])) {
2935
			$paaifip = get_interface_ip($interface);
2936
			if (!is_ipaddr($paaifip)) {
2937
				return;
2938
			}
2939
			$vipif = get_real_interface($interface);
2940
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2941
			$args .= $vipif . " auto";
2942
			foreach ($paa[$interface] as $paent) {
2943
				if (isset($paent['subnet'])) {
2944
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2945
				} elseif (isset($paent['range'])) {
2946
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2947
				}
2948
			}
2949
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2950
		}
2951
	} elseif (count($paa) > 0) {
2952
		foreach ($paa as $paif => $paents) {
2953
			$paaifip = get_interface_ip($paif);
2954
			if (!is_ipaddr($paaifip)) {
2955
				continue;
2956
			}
2957
			$vipif = get_real_interface($paif);
2958
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2959
			$args .= $vipif . " auto";
2960
			foreach ($paents as $paent) {
2961
				if (isset($paent['subnet'])) {
2962
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2963
				} elseif (isset($paent['range'])) {
2964
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2965
				}
2966
			}
2967
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2968
		}
2969
	}
2970
}
2971

    
2972
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2973
	$vips = config_get_path('virtualip/vip');
2974
	if (is_array($vips)) {
2975
		foreach ($vips as $vip) {
2976

    
2977
			$iface = $vip['interface'];
2978
			if (substr($iface, 0, 4) == "_vip")
2979
				$iface = get_configured_vip_interface($vip['interface']);
2980
			if ($iface != $interface)
2981
				continue;
2982
			if ($type == VIP_CARP) {
2983
				if ($vip['mode'] != "carp")
2984
					continue;
2985
			} elseif ($type == VIP_IPALIAS) {
2986
				if ($vip['mode'] != "ipalias")
2987
					continue;
2988
			} else {
2989
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
2990
					continue;
2991
			}
2992

    
2993
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
2994
				interface_vip_bring_down($vip);
2995
			elseif ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
2996
				interface_vip_bring_down($vip);
2997
			elseif ($inet == "all")
2998
				interface_vip_bring_down($vip);
2999
		}
3000
	}
3001
}
3002

    
3003
function interfaces_vips_configure($interface = "") {
3004
	if (config_get_path('system/developerspew')) {
3005
		$mt = microtime();
3006
		echo "interfaces_vips_configure() being called $mt\n";
3007
	}
3008

    
3009
	$vips = config_get_path('virtualip/vip');
3010
	if (!is_array($vips)) {
3011
		return;
3012
	}
3013

    
3014
	$carp_configured = false;
3015
	$anyproxyarp = false;
3016
	foreach ($vips as $vip) {
3017
		if ($interface <> "" &&
3018
		    get_root_interface($vip['interface']) <> $interface) {
3019
			continue;
3020
		}
3021
		switch ($vip['mode']) {
3022
			case "proxyarp":
3023
				/*
3024
				 * nothing it is handled on
3025
				 * interface_proxyarp_configure()
3026
				 */
3027
				$anyproxyarp = true;
3028
				break;
3029
			case "ipalias":
3030
				interface_ipalias_configure($vip);
3031
				break;
3032
			case "carp":
3033
				if ($carp_configured == false) {
3034
					$carp_configured = true;
3035
				}
3036
				interface_carp_configure($vip);
3037
				break;
3038
		}
3039
	}
3040
	/* interfaces_sync_setup() is directly called in rc.bootup*/
3041
	if (!is_platform_booting() && $carp_configured == true) {
3042
		interfaces_sync_setup();
3043
	}
3044
	if ($anyproxyarp == true) {
3045
		interface_proxyarp_configure();
3046
	}
3047
}
3048

    
3049
function interface_ipalias_configure(&$vip) {
3050
	$gateway = '';
3051
	if ($vip['mode'] != 'ipalias') {
3052
		return;
3053
	}
3054

    
3055
	$realif = get_real_interface("_vip{$vip['uniqid']}");
3056
	if ($realif != "lo0") {
3057
		$if = convert_real_interface_to_friendly_interface_name($realif);
3058
		if (!config_path_enabled("interfaces/{$if}")) {
3059
			return;
3060
		}
3061
		if (is_pseudo_interface($realif)) {
3062
			if (is_ipaddrv4($vip['subnet'])) {
3063
				$gateway = get_interface_gateway($if);
3064
			} else {
3065
				$gateway = get_interface_gateway_v6($if);
3066
			}
3067
		}
3068
	}
3069

    
3070
	$af = 'inet';
3071
	if (is_ipaddrv6($vip['subnet'])) {
3072
		$af = 'inet6';
3073
	}
3074
	$iface = $vip['interface'];
3075
	$vhid = '';
3076
	if (substr($vip['interface'], 0, 4) == "_vip") {
3077
		$carpvip = get_configured_vip($vip['interface']);
3078
		$iface = $carpvip['interface'];
3079
		$vhid = "vhid {$carpvip['vhid']}";
3080
	}
3081
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$gateway} {$vhid}");
3082
	unset($iface, $af, $realif, $carpvip, $vhid, $gateway);
3083
}
3084

    
3085
function interface_carp_configure(&$vip, $maintenancemode_only = false, $ipalias_reload = false) {
3086
	if (config_get_path('system/developerspew')) {
3087
		$mt = microtime();
3088
		echo "interface_carp_configure() being called $mt\n";
3089
	}
3090

    
3091
	if ($vip['mode'] != "carp") {
3092
		return;
3093
	}
3094

    
3095
	$realif = get_real_interface($vip['interface']);
3096
	if (!does_interface_exist($realif)) {
3097
		file_notice("CARP", sprintf(gettext(
3098
		    "Interface specified for the virtual IP address %s does not exist. Skipping this VIP."),
3099
		    $vip['subnet']), "Firewall: Virtual IP", "");
3100
		return;
3101
	}
3102
	if ($realif != "lo0") {
3103
		if (!config_path_enabled("interfaces/{$vip['interface']}")) {
3104
			return;
3105
		}
3106
	}
3107

    
3108
	$vip_password = $vip['password'];
3109
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3110
	    $vip_password)));
3111
	if ($vip['password'] != "") {
3112
		$password = " pass {$vip_password}";
3113
	}
3114

    
3115
	$advbase = "";
3116
	if (!empty($vip['advbase'])) {
3117
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3118
	}
3119

    
3120
	$carp_maintenancemode = config_path_enabled('/','virtualip_carp_maintenancemode');
3121
	if ($carp_maintenancemode) {
3122
		$advskew = "advskew 254";
3123
	} else {
3124
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3125
	}
3126

    
3127
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) .
3128
	    " {$advskew} {$advbase} {$password}");
3129

    
3130
	if (!$maintenancemode_only) {
3131
		if (is_ipaddrv4($vip['subnet'])) {
3132
			mwexec("/sbin/ifconfig {$realif} " .
3133
			    escapeshellarg($vip['subnet']) . "/" .
3134
			    escapeshellarg($vip['subnet_bits']) .
3135
			    " alias vhid " . escapeshellarg($vip['vhid']));
3136
		} elseif (is_ipaddrv6($vip['subnet'])) {
3137
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3138
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3139
			    escapeshellarg($vip['subnet_bits']) .
3140
			    " alias vhid " . escapeshellarg($vip['vhid']));
3141
		}
3142
	}
3143

    
3144
	/* reconfigure stacked IP Aliases after CARP VIP changes
3145
	 * see https://redmine.pfsense.org/issues/12227
3146
	 * and https://redmine.pfsense.org/issues/12961 */
3147
	if ($ipalias_reload) {
3148
		foreach (config_get_path('virtualip/vip', []) as $viface) {
3149
			if (($viface['mode'] == 'ipalias') &&
3150
			    (get_root_interface($viface['interface']) == $vip['interface'])) {
3151
				interface_vip_bring_down($viface);
3152
				interface_ipalias_configure($viface);
3153
			}
3154
		}
3155
	}
3156

    
3157
	return $realif;
3158
}
3159

    
3160
function interface_wireless_clone($realif, $wlcfg) {
3161
	global $g;
3162
	/*   Check to see if interface has been cloned as of yet.
3163
	 *   If it has not been cloned then go ahead and clone it.
3164
	 */
3165
	$needs_clone = false;
3166
	if (is_array($wlcfg['wireless'])) {
3167
		$wlcfg_mode = $wlcfg['wireless']['mode'];
3168
	} else {
3169
		$wlcfg_mode = $wlcfg['mode'];
3170
	}
3171
	switch ($wlcfg_mode) {
3172
		case "hostap":
3173
			$mode = "wlanmode hostap";
3174
			break;
3175
		case "adhoc":
3176
			$mode = "wlanmode adhoc";
3177
			break;
3178
		default:
3179
			$mode = "";
3180
			break;
3181
	}
3182
	$baseif = interface_get_wireless_base($wlcfg['if']);
3183
	if (does_interface_exist($realif)) {
3184
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
3185
		$ifconfig_str = implode($output);
3186
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
3187
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
3188
			$needs_clone = true;
3189
		}
3190
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
3191
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
3192
			$needs_clone = true;
3193
		}
3194
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
3195
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
3196
			$needs_clone = true;
3197
		}
3198
	} else {
3199
		$needs_clone = true;
3200
	}
3201

    
3202
	if ($needs_clone == true) {
3203
		/* remove previous instance if it exists */
3204
		if (does_interface_exist($realif)) {
3205
			pfSense_interface_destroy($realif);
3206

    
3207
			/* Invalidate cache */
3208
			get_interface_arr(true);
3209
		}
3210

    
3211
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
3212
		// Create the new wlan interface. FreeBSD returns the new interface name.
3213
		// example:  wlan2
3214
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
3215
		if ($ret <> 0) {
3216
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
3217
			return false;
3218
		}
3219
		$newif = trim($out[0]);
3220
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
3221
		pfSense_interface_rename($newif, $realif);
3222
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
3223
	}
3224
	return true;
3225
}
3226

    
3227
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3228

    
3229
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3230
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3231
				 'regdomain', 'regcountry', 'reglocation');
3232

    
3233
	if (!is_interface_wireless($ifcfg['if'])) {
3234
		return;
3235
	}
3236

    
3237
	$baseif = interface_get_wireless_base($ifcfg['if']);
3238

    
3239
	// Sync shared settings for assigned clones
3240
	$iflist = get_configured_interface_list(true);
3241
	foreach ($iflist as $if) {
3242
		if (($baseif == interface_get_wireless_base(config_get_path("interfaces/{$if}/if"))) &&
3243
			($ifcfg['if'] != config_get_path("interfaces/{$if}/if"))) {
3244
			if (config_path_enabled("interfaces/{$if}/wireless", 'standard') || $sync_changes) {
3245
				foreach ($shared_settings as $setting) {
3246
					if ($sync_changes) {
3247
						if (isset($ifcfg['wireless'][$setting])) {
3248
							config_set_path("interfaces/{$if}/wireless/{$setting}",
3249
											$ifcfg['wireless'][$setting]);
3250
						} elseif (!empty(config_get_path("interfaces/{$if}/wireless/{$setting}"))) {
3251
							config_del_path("interfaces/{$if}/wireless/{$setting}");
3252
						}
3253
					} else {
3254
						if (!empty(config_get_path("interfaces/{$if}/wireless/{$setting}"))) {
3255
							$ifcfg['wireless'][$setting] =
3256
							    config_get_path("interfaces/{$if}/wireless/{$setting}");
3257
						} elseif (isset($ifcfg['wireless'][$setting])) {
3258
							unset($ifcfg['wireless'][$setting]);
3259
						}
3260
					}
3261
				}
3262
				if (!$sync_changes) {
3263
					break;
3264
				}
3265
			}
3266
		}
3267
	}
3268

    
3269
	// Read or write settings at shared area
3270
	if (!empty(config_get_path("wireless/interfaces/{$baseif}"))) {
3271
		foreach ($shared_settings as $setting) {
3272
			if ($sync_changes) {
3273
				if (isset($ifcfg['wireless'][$setting])) {
3274
					config_set_path("wireless/interfaces/{$baseif}/{$setting}",
3275
									$ifcfg['wireless'][$setting]);
3276
				} elseif (!empty(config_get_path("wireless/interfaces/{$baseif}/{$setting}"))) {
3277
					config_del_path("wireless/interfaces/{$baseif}/{$setting}");
3278
				}
3279
			} else {
3280
				if (!empty(config_get_path("wireless/interfaces/{$baseif}/{$setting}"))) {
3281
					$ifcfg['wireless'][$setting] = config_get_path("wireless/interfaces/{$baseif}/{$setting}");
3282
				} elseif (isset($ifcfg['wireless'][$setting])) {
3283
					unset($ifcfg['wireless'][$setting]);
3284
				}
3285
			}
3286
		}
3287
	}
3288

    
3289
	// Sync the mode on the clone creation page with the configured mode on the interface
3290
	if (interface_is_wireless_clone($ifcfg['if'])) {
3291
		foreach (config_get_path('wireless/clone', []) as $key => $clone) {
3292
			if ($clone['cloneif'] == $ifcfg['if']) {
3293
				if ($sync_changes) {
3294
					config_set_path("wireless/clone/{$key}/mode", $ifcfg['wireless']['mode']);
3295
				} else {
3296
					$ifcfg['wireless']['mode'] = $clone['mode'];
3297
				}
3298
				break;
3299
			}
3300
		}
3301
		unset($clone);
3302
	}
3303
}
3304

    
3305
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3306
	global $g;
3307

    
3308
	/*    open up a shell script that will be used to output the commands.
3309
	 *    since wireless is changing a lot, these series of commands are fragile
3310
	 *    and will sometimes need to be verified by a operator by executing the command
3311
	 *    and returning the output of the command to the developers for inspection.  please
3312
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3313
	 */
3314

    
3315
	// Remove script file
3316
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3317

    
3318
	// Clone wireless nic if needed.
3319
	interface_wireless_clone($if, $wl);
3320

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

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

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

    
3330
	/* set values for /path/program */
3331
	if (file_exists("/usr/local/sbin/hostapd")) {
3332
		$hostapd = "/usr/local/sbin/hostapd";
3333
	} else {
3334
		$hostapd = "/usr/sbin/hostapd";
3335
	}
3336
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3337
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3338
	} else {
3339
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3340
	}
3341
	$ifconfig = "/sbin/ifconfig";
3342
	$sysctl = "/sbin/sysctl";
3343
	$sysctl_args = "-q";
3344

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

    
3347
	$wlcmd = array();
3348
	$wl_sysctl = array();
3349
	/* Set a/b/g standard */
3350
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3351
	/* skip mode entirely for "auto" */
3352
	if ($wlcfg['standard'] != "auto") {
3353
		$wlcmd[] = "mode " . escapeshellarg($standard);
3354
	}
3355

    
3356
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3357
	 * to prevent massive packet loss under certain conditions. */
3358
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3359
		$wlcmd[] = "-ampdu";
3360
	}
3361

    
3362
	/* Set ssid */
3363
	if ($wlcfg['ssid']) {
3364
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3365
	}
3366

    
3367
	/* Set 802.11g protection mode */
3368
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3369

    
3370
	/* set wireless channel value */
3371
	if (isset($wlcfg['channel'])) {
3372
		if ($wlcfg['channel'] == "0") {
3373
			$wlcmd[] = "channel any";
3374
		} else {
3375
			if ($wlcfg['channel_width'] != "0") {
3376
				$channel_width = ":" . $wlcfg['channel_width'];
3377
			} else {
3378
				$channel_width = '';
3379
			}
3380
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3381
		}
3382
	}
3383

    
3384
	/* Set antenna diversity value */
3385
	if (isset($wlcfg['diversity'])) {
3386
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3387
	}
3388

    
3389
	/* Set txantenna value */
3390
	if (isset($wlcfg['txantenna'])) {
3391
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3392
	}
3393

    
3394
	/* Set rxantenna value */
3395
	if (isset($wlcfg['rxantenna'])) {
3396
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3397
	}
3398

    
3399
	/* set Distance value */
3400
	if ($wlcfg['distance']) {
3401
		$distance = escapeshellarg($wlcfg['distance']);
3402
	}
3403

    
3404
	/* Set wireless hostap mode */
3405
	if ($wlcfg['mode'] == "hostap") {
3406
		$wlcmd[] = "mediaopt hostap";
3407
	} else {
3408
		$wlcmd[] = "-mediaopt hostap";
3409
	}
3410

    
3411
	/* Set wireless adhoc mode */
3412
	if ($wlcfg['mode'] == "adhoc") {
3413
		$wlcmd[] = "mediaopt adhoc";
3414
	} else {
3415
		$wlcmd[] = "-mediaopt adhoc";
3416
	}
3417

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

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

    
3427
	/* handle pureg (802.11g) only option */
3428
	if (isset($wlcfg['pureg']['enable'])) {
3429
		$wlcmd[] = "mode 11g pureg";
3430
	} else {
3431
		$wlcmd[] = "-pureg";
3432
	}
3433

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

    
3441
	/* enable apbridge option */
3442
	if (isset($wlcfg['apbridge']['enable'])) {
3443
		$wlcmd[] = "apbridge";
3444
	} else {
3445
		$wlcmd[] = "-apbridge";
3446
	}
3447

    
3448
	/* handle turbo option */
3449
	if (isset($wlcfg['turbo']['enable'])) {
3450
		$wlcmd[] = "mediaopt turbo";
3451
	} else {
3452
		$wlcmd[] = "-mediaopt turbo";
3453
	}
3454

    
3455
	/* handle txpower setting */
3456
	// or don't. this has issues at the moment.
3457
	/*
3458
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3459
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3460
	}*/
3461

    
3462
	/* handle wme option */
3463
	if (isset($wlcfg['wme']['enable'])) {
3464
		$wlcmd[] = "wme";
3465
	} else {
3466
		$wlcmd[] = "-wme";
3467
	}
3468

    
3469
	/* Enable wpa if it's configured. No WEP support anymore. */
3470
	if (isset($wlcfg['wpa']['enable'])) {
3471
		$wlcmd[] = "authmode wpa wepmode off ";
3472
	} else {
3473
		$wlcmd[] = "authmode open wepmode off ";
3474
	}
3475

    
3476
	kill_hostapd($if);
3477
	mwexec(kill_wpasupplicant("{$if}"));
3478

    
3479
	$wpa_supplicant_file = "{$g['varetc_path']}/wpa_supplicant_{$if}.";
3480
	$hostapd_conf = "{$g['varetc_path']}/hostapd_{$if}.conf";
3481

    
3482
	unlink_if_exists("{$wpa_supplicant_file}*");
3483
	unlink_if_exists($hostapd_conf);
3484

    
3485
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3486
	$wpa = "";
3487
	switch ($wlcfg['mode']) {
3488
		case 'bss':
3489
			if (isset($wlcfg['wpa']['enable'])) {
3490
				$wpa .= <<<EOD
3491
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3492
ctrl_interface_group=0
3493
ap_scan=1
3494
#fast_reauth=1
3495
network={
3496
ssid="{$wlcfg['ssid']}"
3497
scan_ssid=1
3498
priority=5
3499
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3500
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3501
group={$wlcfg['wpa']['wpa_pairwise']}
3502

    
3503
EOD;
3504
				if ($wlcfg['wpa']['wpa_key_mgmt'] == 'WPA-EAP') {
3505
					if (($wlcfg['wpa']['wpa_eap_client_mode'] == 'PEAP') ||
3506
					    ($wlcfg['wpa']['wpa_eap_client_mode'] == 'TTLS')) {
3507
						if ($wlcfg['wpa']['wpa_eap_inner_auth'] == 'MSCHAPV2') {
3508
							$wpa .= "phase1=\"peaplabel=0\"\n";
3509
						}
3510
						$wpa .= "phase2=\"auth={$wlcfg['wpa']['wpa_eap_inner_auth']}\"\n";
3511
						$wpa .= "identity=\"{$wlcfg['wpa']['wpa_eap_inner_id']}\"\n";
3512
						$eappass = base64_decode($wlcfg['wpa']['wpa_eap_inner_password']);
3513
						$wpa .= "password=\"{$eappass}\"\n";
3514
					}
3515
					if (strstr($wlcfg['wpa']['wpa_eap_client_mode'], 'TLS')) {
3516
						$cert = lookup_cert($wlcfg['wpa']['wpa_eap_cert']);
3517
						$cert = $cert['item'];
3518
						$wpa_supplicant_crt = $wpa_supplicant_file . "crt";
3519
						$wpa_supplicant_key = $wpa_supplicant_file . "key";
3520
						@file_put_contents($wpa_supplicant_crt, base64_decode($cert['crt']) . "\n" .
3521
						    ca_chain($cert));
3522
						@file_put_contents($wpa_supplicant_key, base64_decode($cert['prv']));
3523
						@chmod($wpa_supplicant_crt, 0600);
3524
						@chmod($wpa_supplicant_key, 0600);
3525
						$wpa .= "client_cert=\"{$wpa_supplicant_crt}\"\n";
3526
						$wpa .= "private_key=\"{$wpa_supplicant_key}\"\n";
3527
					}
3528
					$ca = lookup_ca($wlcfg['wpa']['wpa_eap_ca']);
3529
					$ca = $ca['item'];
3530
					$wpa_supplicant_ca = $wpa_supplicant_file . "ca";
3531
					@file_put_contents($wpa_supplicant_ca, base64_decode($ca['crt']) . "\n" .
3532
					    ca_chain($ca));
3533
					$wpa .= "ca_cert=\"{$wpa_supplicant_ca}\"\n";
3534
					$wpa .= "eap={$wlcfg['wpa']['wpa_eap_client_mode']}\n";
3535
				} else {
3536
					$wpa .= "psk=\"{$wlcfg['wpa']['passphrase']}\"\n";
3537
				}
3538
				$wpa .= "}\n";
3539

    
3540
				@file_put_contents($wpa_supplicant_file . "conf", $wpa);
3541
				unset($wpa);
3542
			}
3543
			break;
3544
		case 'hostap':
3545
			if (!empty($wlcfg['wpa']['passphrase'])) {
3546
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3547
			} else {
3548
				$wpa_passphrase = "";
3549
			}
3550
			if (isset($wlcfg['wpa']['enable'])) {
3551
				$wpa .= <<<EOD
3552
interface={$if}
3553
driver=bsd
3554
logger_syslog=-1
3555
logger_syslog_level=0
3556
logger_stdout=-1
3557
logger_stdout_level=0
3558
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3559
ctrl_interface={$g['varrun_path']}/hostapd
3560
ctrl_interface_group=wheel
3561
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3562
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3563
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3564
ssid={$wlcfg['ssid']}
3565
debug={$wlcfg['wpa']['debug_mode']}
3566
wpa={$wlcfg['wpa']['wpa_mode']}
3567
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3568
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3569
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3570
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3571
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3572
{$wpa_passphrase}
3573

    
3574
EOD;
3575

    
3576
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3577
					$wpa .= <<<EOD
3578
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3579
rsn_preauth=1
3580
rsn_preauth_interfaces={$if}
3581

    
3582
EOD;
3583
				}
3584
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3585
					$wpa .= "ieee8021x=1\n";
3586

    
3587
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3588
						$auth_server_port = "1812";
3589
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3590
							$auth_server_port = intval($wlcfg['auth_server_port']);
3591
						}
3592
						$wpa .= <<<EOD
3593

    
3594
auth_server_addr={$wlcfg['auth_server_addr']}
3595
auth_server_port={$auth_server_port}
3596
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3597

    
3598
EOD;
3599
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3600
							$auth_server_port2 = "1812";
3601
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3602
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3603
							}
3604

    
3605
							$wpa .= <<<EOD
3606
auth_server_addr={$wlcfg['auth_server_addr2']}
3607
auth_server_port={$auth_server_port2}
3608
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3609

    
3610
EOD;
3611
						}
3612
					}
3613
				}
3614

    
3615
				@file_put_contents($hostapd_conf, $wpa);
3616
				unset($wpa);
3617
			}
3618
			break;
3619
	}
3620

    
3621
	/*
3622
	 *    all variables are set, lets start up everything
3623
	 */
3624

    
3625
	$baseif = interface_get_wireless_base($if);
3626
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3627
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3628

    
3629
	/* set sysctls for the wireless interface */
3630
	if (!empty($wl_sysctl)) {
3631
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3632
		foreach ($wl_sysctl as $wl_sysctl_line) {
3633
			fwrite($fd_set, "{$sysctl} {$sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3634
		}
3635
	}
3636

    
3637
	/* set ack timers according to users preference (if he/she has any) */
3638
	if ($distance) {
3639
		fwrite($fd_set, "# Enable ATH distance settings\n");
3640
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3641
	}
3642

    
3643
	if (isset($wlcfg['wpa']['enable'])) {
3644
		if ($wlcfg['mode'] == "bss") {
3645
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3646
		}
3647
		if ($wlcfg['mode'] == "hostap") {
3648
			/* add line to script to restore old mac to make hostapd happy */
3649
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3650
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3651
				$if_curmac = get_interface_mac($if);
3652
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3653
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3654
						" link " . escapeshellarg($if_oldmac) . "\n");
3655
				}
3656
			}
3657

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

    
3660
			/* add line to script to restore spoofed mac after running hostapd */
3661
			if ($wl['spoofmac']) {
3662
				$if_curmac = get_interface_mac($if);
3663
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3664
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3665
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3666
				}
3667
			}
3668
		}
3669
	}
3670

    
3671
	fclose($fd_set);
3672

    
3673
	/* Making sure regulatory settings have actually changed
3674
	 * before applying, because changing them requires bringing
3675
	 * down all wireless networks on the interface. */
3676
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3677
	$ifconfig_str = implode($output);
3678
	unset($output);
3679
	$reg_changing = false;
3680

    
3681
	/* special case for the debug country code */
3682
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3683
		$reg_changing = true;
3684
	} elseif ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3685
		$reg_changing = true;
3686
	} elseif ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3687
		$reg_changing = true;
3688
	} elseif ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3689
		$reg_changing = true;
3690
	} elseif ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3691
		$reg_changing = true;
3692
	}
3693

    
3694
	if ($reg_changing) {
3695
		/* set regulatory domain */
3696
		if ($wlcfg['regdomain']) {
3697
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3698
		}
3699

    
3700
		/* set country */
3701
		if ($wlcfg['regcountry']) {
3702
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3703
		}
3704

    
3705
		/* set location */
3706
		if ($wlcfg['reglocation']) {
3707
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3708
		}
3709

    
3710
		$wlregcmd_args = implode(" ", $wlregcmd);
3711

    
3712
		/* build a complete list of the wireless clones for this interface */
3713
		$clone_list = array();
3714
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3715
			$clone_list[] = interface_get_wireless_clone($baseif);
3716
		}
3717
		foreach (config_get_path('wireless/clone', []) as $clone) {
3718
			if ($clone['if'] == $baseif) {
3719
				$clone_list[] = $clone['cloneif'];
3720
			}
3721
		}
3722

    
3723
		/* find which clones are up and bring them down */
3724
		$clones_up = array();
3725
		foreach ($clone_list as $clone_if) {
3726
			$clone_status = get_interface_addresses($clone_if);
3727
			if ($clone_status['status'] == 'up') {
3728
				$clones_up[] = $clone_if;
3729
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3730
			}
3731
		}
3732

    
3733
		/* apply the regulatory settings */
3734
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3735
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3736

    
3737
		/* bring the clones back up that were previously up */
3738
		foreach ($clones_up as $clone_if) {
3739
			interfaces_bring_up($clone_if);
3740

    
3741
			/*
3742
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3743
			 * is in infrastructure mode, and WPA is enabled.
3744
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3745
			 */
3746
			if ($clone_if != $if) {
3747
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3748
				if ((!empty($friendly_if)) &&
3749
				    (config_get_path("interfaces/{$friendly_if}/wireless/mode") == "bss") &&
3750
				    config_path_enabled("interfaces/{$friendly_if}/wireless/wpa")) {
3751
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3752
				}
3753
			}
3754
		}
3755
	}
3756

    
3757
	/* The mode must be specified in a separate command before ifconfig
3758
	 * will allow the mode and channel at the same time in the next.
3759
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3760
	 */
3761
	if ($wlcfg['mode'] == "hostap") {
3762
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3763
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3764
	}
3765

    
3766
	/* configure wireless */
3767
	$wlcmd_args = implode(" ", $wlcmd);
3768
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args);
3769
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3770
	/* Bring the interface up only after setting up all the other parameters. */
3771
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up");
3772
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3773
	fclose($wlan_setup_log);
3774

    
3775
	unset($wlcmd_args, $wlcmd);
3776

    
3777

    
3778
	sleep(1);
3779
	/* execute hostapd and wpa_supplicant if required in shell */
3780
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3781

    
3782
	return 0;
3783

    
3784
}
3785

    
3786
function kill_hostapd($interface) {
3787
	global $g;
3788

    
3789
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3790
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3791
	}
3792
}
3793

    
3794
function kill_wpasupplicant($interface) {
3795
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3796
}
3797

    
3798
function find_dhclient_process($interface) {
3799
	if ($interface) {
3800
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3801
	} else {
3802
		$pid = 0;
3803
	}
3804

    
3805
	return intval($pid);
3806
}
3807

    
3808
function kill_dhclient_process($interface) {
3809
	if (empty($interface) || !does_interface_exist($interface)) {
3810
		return;
3811
	}
3812

    
3813
	$i = 0;
3814
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3815
		/* 3rd time make it die for sure */
3816
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3817
		posix_kill($pid, $sig);
3818
		sleep(1);
3819
		$i++;
3820
	}
3821
	unset($i);
3822

    
3823
	unlink_if_exists(g_get('vardb_path') . "/{$interface}_cacheip");
3824
}
3825

    
3826
function find_dhcp6c_process() {
3827
	global $g;
3828

    
3829
	if (isvalidpid("{$g['varrun_path']}/dhcp6c.pid")) {
3830
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c.pid"), " \n");
3831
	} else {
3832
		return(false);
3833
	}
3834

    
3835
	return intval($pid);
3836
}
3837

    
3838
function kill_dhcp6client_process($force, $release = false) {
3839
	global $g;
3840

    
3841
	$i = 0;
3842

    
3843
	/*
3844
	Beware of the following: Reason, the interface may be down, but
3845
	dhcp6c may still be running, it just complains it cannot send
3846
	and carries on. Commented out as will stop the call to kill.
3847

    
3848
	if (empty($interface) || !does_interface_exist($interface)) {
3849
		return;
3850
	}
3851
	*/
3852

    
3853
	/*********** Notes on signals for dhcp6c and this function *************
3854

    
3855
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3856
	a release and waiting for the response that never comes.
3857
	So we need to tell it that the interface is down and to just die quickly
3858
	otherwise a new client may launch and we have duplicate processes.
3859
	In this case use SIGUSR1.
3860

    
3861
	If we want to exit normally obeying the no release flag then use SIGTERM.
3862
	If we want to exit with a release overriding the no release flag then
3863
	use SIGUSR2.
3864

    
3865
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3866
	exit quickly without sending release signals.
3867

    
3868
	If $Force is set to false and $release is also set to false dhcp6c will
3869
	follow the no-release flag.
3870

    
3871
	If $Force is set to false and $release is true then dhcp6c will send a
3872
	release regardless of the no-release flag.
3873
	***********************************************************************/
3874

    
3875
	if ($force == true) {
3876
		$psig=SIGUSR1;
3877
	} elseif ($release == false) {
3878
		$psig=SIGTERM;
3879
	} else {
3880
		$psig=SIGUSR2;
3881
	}
3882

    
3883
	while ((($pid = find_dhcp6c_process()) != 0) && ($i < 3)) {
3884
		/* 3rd time make it die for sure */
3885
		$sig = ($i == 2 ? SIGKILL : $psig);
3886
		posix_kill($pid, $sig);
3887
		sleep(1);
3888
		$i++;
3889
	}
3890
	/* Clear the RTSOLD script created lock & tidy up */
3891
	unlink_if_exists("/tmp/dhcp6c_lock");
3892
	unlink_if_exists("{$g['varrun_path']}/dhcp6c.pid"); // just in case!
3893
}
3894
function reset_dhcp6client_process() {
3895

    
3896
	$pid = find_dhcp6c_process();
3897

    
3898
	if($pid != 0) {
3899
		posix_kill($pid, SIGHUP);
3900
	}
3901
}
3902

    
3903
function run_dhcp6client_process($interfaces, $debugOption, $noreleaseOption) {
3904
	global $g;
3905

    
3906
	/*
3907
	 * Only run this if the lock does not exist. In theory the lock being
3908
	 * there in this mode means the user has selected dhcp6withoutRA while
3909
	 * a session is active in the other mode.
3910
	 *
3911
	 * It should not happen as the process should have been killed and the
3912
	 * lock deleted.
3913
	 */
3914

    
3915
	if (!file_exists("/tmp/dhcp6c_lock")) {
3916
		kill_dhcp6client_process(true);
3917
		/* Lock it to avoid multiple runs */
3918
		touch("/tmp/dhcp6c_lock");
3919
		mwexec("/usr/local/sbin/dhcp6c {$debugOption} " .
3920
		    "{$noreleaseOption} " .
3921
		    "-c {$g['varetc_path']}/dhcp6c.conf " .
3922
		    "-p {$g['varrun_path']}/dhcp6c.pid " .
3923
		    implode(' ', $interfaces));
3924
		log_error(sprintf(gettext(
3925
		    "Starting DHCP6 client for interfaces %s in DHCP6 without RA mode"),
3926
		    implode(',', $interfaces)));
3927
	}
3928
}
3929

    
3930
function interface_virtual_create($interface) {
3931
	$vlan = interface_is_vlan($interface);
3932
	if ($vlan != NULL) {
3933
		interface_vlan_configure($vlan);
3934
	} elseif (substr($interface, 0, 3) == "gre") {
3935
		interfaces_tunnel_configure(0, $interface, 'gre');
3936
	} elseif (substr($interface, 0, 3) == "gif") {
3937
		interfaces_tunnel_configure(0, $interface, 'gif');
3938
	} elseif (substr($interface, 0, 5) == "ovpns") {
3939
		foreach (config_get_path('openvpn/openvpn-server', []) as $server) {
3940
			if ($interface == "ovpns{$server['vpnid']}") {
3941
				if (!function_exists('openvpn_resync')) {
3942
					require_once('openvpn.inc');
3943
				}
3944
				log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3945
				openvpn_resync('server', $server);
3946
			}
3947
		}
3948
		unset($server);
3949
	} elseif (substr($interface, 0, 5) == "ovpnc") {
3950
		foreach (config_get_path('openvpn/openvpn-client', []) as $client) {
3951
			if ($interface == "ovpnc{$client['vpnid']}") {
3952
				if (!function_exists('openvpn_resync')) {
3953
					require_once('openvpn.inc');
3954
				}
3955
				log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3956
				openvpn_resync('client', $client);
3957
			}
3958
		}
3959
		unset($client);
3960
	} elseif (substr($interface, 0, 5) == "ipsec") {
3961
		foreach (config_get_path('ipsec/phase1', []) as $ph1ent) {
3962
			if ($ph1ent['disabled']) {
3963
				continue;
3964
			}
3965
			interface_ipsec_vti_configure($ph1ent);
3966
		}
3967
	} elseif (substr($interface, 0, 4) == "lagg") {
3968
		interfaces_lagg_configure($interface);
3969
	} elseif (substr($interface, 0, 6) == "bridge") {
3970
		interfaces_bridge_configure(0, $interface);
3971
	}
3972
}
3973

    
3974
function interface_vlan_mtu_configured($iface) {
3975

    
3976
	$mtu = 0;
3977
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
3978

    
3979
		if ($vlan['vlanif'] != $iface)
3980
			continue;
3981

    
3982
		$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
3983
		$parentinf = convert_real_interface_to_friendly_interface_name($vlan['if']);
3984
		if (!empty($assignedport) && !empty(config_get_path("interfaces/{$assignedport}/mtu"))) {
3985
			/* VLAN MTU */
3986
			$mtu = config_get_path("interfaces/{$assignedport}/mtu");
3987
		} elseif (!empty(config_get_path("interfaces/{$parentinf}/mtu"))) {
3988
			/* Parent MTU */
3989
			$mtu = config_get_path("interfaces/{$parentinf}/mtu");
3990
		}
3991
	}
3992

    
3993
	return $mtu;
3994
}
3995

    
3996
function interface_mtu_wanted_for_pppoe($realif) {
3997

    
3998
	$mtu = 0;
3999
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
4000
		if ($ppp['type'] != "pppoe") {
4001
			continue;
4002
		}
4003

    
4004
		$mtus = array();
4005
		if (!empty($ppp['mtu'])) {
4006
			$mtus = explode(',', $ppp['mtu']);
4007
		}
4008
		$ports = explode(',', $ppp['ports']);
4009

    
4010
		foreach ($ports as $pid => $port) {
4011
			$parentifa = get_parent_interface($port);
4012
			$parentif = $parentifa[0];
4013
			if ($parentif != $realif)
4014
				continue;
4015

    
4016
			// there is an MTU configured on the port in question
4017
			if (!empty($mtus[$pid])) {
4018
				$mtu = intval($mtus[$pid]) + 8;
4019
			// or use the MTU configured on the interface ...
4020
			} else {
4021
				foreach (config_get_path('interfaces', []) as $interface) {
4022
					if ($interface['if'] == $ppp['if'] &&
4023
					    !empty($interface['mtu'])) {
4024
						$mtu = intval($interface['mtu']) + 8;
4025
						break;
4026
					}
4027
				}
4028
			}
4029
		}
4030
	}
4031

    
4032
	return $mtu;
4033
}
4034

    
4035
/**
4036
 * Applies the configured settings for an interface.
4037
 * 
4038
 * @param bool $skip_parent_mtu Skip setting the parent interface's MTU
4039
 */
4040
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false, $skip_parent_mtu = false) {
4041
	global $g;
4042
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
4043
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
4044

    
4045
	$wancfg = config_get_path("interfaces/{$interface}");
4046

    
4047
	if (!isset($wancfg['enable'])) {
4048
		return;
4049
	}
4050

    
4051
	$realif = get_real_interface($interface);
4052
	$realhwif_array = get_parent_interface($interface);
4053
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
4054
	$realhwif = $realhwif_array[0];
4055

    
4056
	$mac_if_cfg = $wancfg;
4057
	if (interface_is_vlan($realif)) {
4058
		$mac_if = convert_real_interface_to_friendly_interface_name(
4059
		    $realhwif);
4060
		if (is_array(config_get_path("interfaces/{$mac_if}"))) {
4061
			$mac_if_cfg = config_get_path("interfaces/{$mac_if}");
4062
		} else {
4063
			$mac_if = $interface;
4064
		}
4065
	}
4066

    
4067
	if (!is_platform_booting() && (substr($realif, 0, 4) != "ovpn") && (substr($realif, 0, 5) != "ipsec")) {
4068
		/* remove all IPv4 and IPv6 addresses */
4069
		$tmpifaces = pfSense_getall_interface_addresses($realif);
4070
		if (is_array($tmpifaces)) {
4071
			foreach ($tmpifaces as $tmpiface) {
4072
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
4073
					if (!is_linklocal($tmpiface)) {
4074
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
4075
					}
4076
				} elseif (strstr($tmpiface, "fe80::1:1")) {
4077
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 fe80::1:1 -alias");
4078
				} else {
4079
					if (is_subnetv4($tmpiface)) {
4080
						$tmpip = explode('/', $tmpiface);
4081
						$tmpip = $tmpip[0];
4082
					} else {
4083
						$tmpip = $tmpiface;
4084
					}
4085
					pfSense_interface_deladdress($realif, $tmpip);
4086
				}
4087
			}
4088
		}
4089

    
4090
		/* only bring down the interface when both v4 and v6 are set to NONE */
4091
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
4092
			interface_bring_down($interface);
4093
		}
4094
	}
4095

    
4096
	$interface_to_check = $realif;
4097
	if (interface_isppp_type($interface)) {
4098
		$interface_to_check = $realhwif;
4099
	}
4100

    
4101
	/* Need to check that the interface exists or not in the case where its coming back from disabled state see #3270 */
4102
	if (!is_platform_booting() && (in_array(substr($realif, 0, 3), array("gre", "gif")) ||
4103
	    !does_interface_exist($interface_to_check))) {
4104
		interface_virtual_create($interface_to_check);
4105
	}
4106

    
4107
	/* Disable Accepting router advertisements unless specifically requested */
4108
	if (g_get('debug')) {
4109
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
4110
	}
4111
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
4112
	{
4113
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
4114
	}
4115
	/* wireless configuration? */
4116
	if (is_array($wancfg['wireless']) && !$linkupevent) {
4117
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
4118
	}
4119

    
4120
	$current_mac = get_interface_mac($realhwif);
4121
	$vendor_mac = get_interface_vendor_mac($realhwif);
4122

    
4123
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
4124
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
4125

    
4126
		interface_set_macaddr($realhwif, $mac_addr);
4127

    
4128
		/* Regenerate link-local address on MAC change.
4129
		 *
4130
		 * Some network devices respond to a DHCPv6 Solicit message only when
4131
		 * the IPv6 source address is consistent with what they expect.
4132
		 *
4133
		 * See https://redmine.pfsense.org/issues/12794 */
4134
		if ($mac_addr != $current_mac) {
4135
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 ifdisabled");
4136
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 " . get_interface_linklocal($interface) . " delete");
4137
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -ifdisabled");
4138
		}
4139
	} else {
4140
		/*
4141
		 * this is not a valid mac address.  generate a
4142
		 * temporary mac address so the machine can get online.
4143
		 */
4144
		echo gettext("Generating new MAC address.");
4145
		$random_mac = generate_random_mac_address();
4146
		interface_set_macaddr($realhwif, $random_mac);
4147
		config_set_path("interfaces/{$mac_if}/spoofmac", $random_mac);
4148
		write_config(sprintf(gettext('The invalid MAC address ' .
4149
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
4150
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
4151
		file_notice("MAC Address altered", sprintf(gettext('The ' .
4152
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
4153
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
4154
		    $random_mac), "Interfaces");
4155
	}
4156

    
4157
	/* media */
4158
	if ($wancfg['media'] || $wancfg['mediaopt']) {
4159
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
4160
		if ($wancfg['media']) {
4161
			$cmd .= " media " . escapeshellarg($wancfg['media']);
4162
		}
4163
		if ($wancfg['mediaopt']) {
4164
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
4165
		}
4166
		mwexec($cmd);
4167
	}
4168

    
4169
	/* Apply hw offloading policies as configured */
4170
	enable_hardware_offloading($interface);
4171

    
4172
	/* invalidate interface/ip/sn cache */
4173
	get_interface_arr(true);
4174
	unset($interface_ip_arr_cache[$realif]);
4175
	unset($interface_sn_arr_cache[$realif]);
4176
	unset($interface_ipv6_arr_cache[$realif]);
4177
	unset($interface_snv6_arr_cache[$realif]);
4178

    
4179
	$tunnelif = substr($realif, 0, 3);
4180

    
4181
	$mtuif = $realif;
4182
	$mtuhwif = $realhwif;
4183

    
4184
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
4185
	if (interface_isppp_type($interface)) {
4186
		$mtuif = $realhwif;
4187
		$mtuhwif_array = get_parent_interface($mtuif);
4188
		$mtuhwif = $mtuhwif_array[0];
4189
	}
4190

    
4191
	$wantedmtu = 0;
4192
	foreach (config_get_path('interfaces', []) as $tmpinterface) {
4193
		if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
4194
			$wantedmtu = $tmpinterface['mtu'];
4195
			break;
4196
		}
4197
	}
4198

    
4199
	/* MTU is not specified for interface, try the pppoe settings. */
4200
	if ($wantedmtu == 0) {
4201
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
4202
	}
4203
	if (($wantedmtu == 0) && (interface_is_vlan($mtuif) != NULL) && interface_isppp_type($interface)) {
4204
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
4205
	}
4206
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gre')) {
4207
		/* set MTU to 1400 for GRE over IPsec */
4208
		if (is_greipsec($mtuif)) {
4209
			$wantedmtu = 1400;
4210
		} else {
4211
			$wantedmtu = 1476;
4212
		}
4213
	}
4214
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gif')) {
4215
		$wantedmtu = 1280;
4216
	}
4217

    
4218
	/* Set the MTU to 1500 if no explicit MTU configured. */
4219
	if ($wantedmtu == 0) {
4220
		$wantedmtu = 1500; /* Default */
4221
	}
4222

    
4223
	if (interface_is_vlan($mtuif) != NULL) {
4224
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4225
		if (!empty($assignedparent) && !empty(config_get_path("interfaces/{$assignedparent}/mtu"))) {
4226
			$parentmtu = config_get_path("interfaces/{$assignedparent}/mtu");
4227
			if ($wancfg['mtu'] > $parentmtu) {
4228
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4229
			}
4230
		}
4231

    
4232
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4233

    
4234
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4235
			$configuredmtu = $parentmtu;
4236
		if ($configuredmtu != 0)
4237
			$mtu = $configuredmtu;
4238
		else
4239
			$mtu = $wantedmtu;
4240

    
4241
		/* Set the parent MTU. Avoid looping when a parent lagg interface
4242
		   is being configured; see #14083 */
4243
		if ((get_interface_mtu($mtuhwif) < $mtu) && !$skip_parent_mtu)
4244
			set_interface_mtu($mtuhwif, $mtu);
4245
		/* Set the VLAN MTU. */
4246
		if (get_interface_mtu($mtuif) != $mtu)
4247
			set_interface_mtu($mtuif, $mtu);
4248
	} elseif (substr($mtuif, 0, 4) == 'lagg') {
4249
		/* LAGG interface must be destroyed and re-created to change MTU */
4250
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4251
			foreach (config_get_path('laggs/lagg', []) as $lagg) {
4252
				if ($lagg['laggif'] == $mtuif) {
4253
					interface_lagg_configure($lagg);
4254
					break;
4255
				}
4256
			}
4257
		}
4258
	} else {
4259
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4260
			pfSense_interface_mtu($mtuif, $wantedmtu);
4261
			set_ipv6routes_mtu($mtuif, $wantedmtu);
4262
		}
4263
	}
4264
	/* XXX: What about gre/gif/.. ? */
4265

    
4266
	if (does_interface_exist($wancfg['if'])) {
4267
		interfaces_bring_up($wancfg['if']);
4268
	}
4269

    
4270
	switch ($wancfg['ipaddr']) {
4271
		case 'dhcp':
4272
			interface_dhcp_configure($interface);
4273
			break;
4274
		case 'pppoe':
4275
		case 'l2tp':
4276
		case 'pptp':
4277
		case 'ppp':
4278
			interface_ppps_configure($interface);
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_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
4284
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
4285
				}
4286
			}
4287
			break;
4288
	}
4289

    
4290
	switch ($wancfg['ipaddrv6']) {
4291
		case 'slaac':
4292
		case 'dhcp6':
4293
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
4294
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
4295
			// handles all non-PPP connections with 'dhcp6usev4iface' set
4296
			log_error(gettext("calling interface_dhcpv6_configure."));
4297
			if ((($wancfg['ipaddrv6'] == 'dhcp6') && !isset($wancfg['dhcp6usev4iface'])) ||
4298
			    (($wancfg['ipaddrv6'] == 'slaac') && !isset($wancfg['slaacusev4iface'])) ||
4299
			    !interface_isppp_type($interface)) {
4300
				interface_dhcpv6_configure($interface, $wancfg);
4301
			}
4302
			break;
4303
		case '6rd':
4304
			interface_6rd_configure($interface, $wancfg);
4305
			break;
4306
		case '6to4':
4307
			interface_6to4_configure($interface, $wancfg);
4308
			break;
4309
		case 'track6':
4310
			interface_track6_configure($interface, $wancfg, $linkupevent);
4311
			break;
4312
		default:
4313
			/* XXX: Kludge for now related to #3280 */
4314
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips", "l2t"))) {
4315
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
4316
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
4317
					// FIXME: Add IPv6 Support to the pfSense module
4318
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
4319
				}
4320
			}
4321
			break;
4322
	}
4323

    
4324
	if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4325
		$bridgetmp = link_interface_to_bridge($interface);
4326
		if (!empty($bridgetmp)) {
4327
			interface_bridge_add_member($bridgetmp, $realif);
4328
		}
4329
	}
4330

    
4331
	if (!is_platform_booting()) {
4332
		link_interface_to_vips($interface, "update");
4333

    
4334
		if ($tunnelif != 'gre') {
4335
			$gre = link_interface_to_tunnelif($interface, 'gre');
4336
			array_walk($gre, 'interface_gre_configure');
4337
		}
4338

    
4339
		if ($tunnelif != 'gif') {
4340
			$gif = link_interface_to_tunnelif($interface, 'gif');
4341
			array_walk($gif, 'interface_gif_configure');
4342
		}
4343

    
4344
		$grouptmp = link_interface_to_group($interface);
4345
		if (!empty($grouptmp)) {
4346
			array_walk($grouptmp, 'interface_group_add_member');
4347
		}
4348

    
4349
		if ($interface == "lan") {
4350
			/* make new hosts file */
4351
			system_hosts_generate();
4352
		}
4353

    
4354
		if ($reloadall == true) {
4355

    
4356
			/* reconfigure static routes (kernel may have deleted them) */
4357
			system_routing_configure($interface);
4358

    
4359
			/* reload ipsec tunnels */
4360
			send_event("service reload ipsecdns");
4361

    
4362
			if (config_path_enabled('dnsmasq')) {
4363
				services_dnsmasq_configure();
4364
			}
4365

    
4366
			if (config_path_enabled('unbound')) {
4367
				services_unbound_configure(true, $interface);
4368
			}
4369

    
4370
			/* update dyndns */
4371
			send_event("service reload dyndns {$interface}");
4372
		}
4373
	}
4374

    
4375
	if (!is_platform_booting() && (substr($realif, 0, 5) == 'l2tps')) {
4376
		vpn_l2tp_configure();
4377
	};
4378

    
4379
	if (!empty($wancfg['descr'])) {
4380
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4381
	};
4382

    
4383
	interfaces_staticarp_configure($interface);
4384
	return 0;
4385
}
4386

    
4387
function interface_track6_configure($interface, $wancfg, $linkupevent = false) {
4388
	global $g;
4389

    
4390
	if (!is_array($wancfg)) {
4391
		return;
4392
	}
4393

    
4394
	if (!isset($wancfg['enable'])) {
4395
		return;
4396
	}
4397

    
4398
	/* If the interface is not configured via another, exit */
4399
	if (empty($wancfg['track6-interface'])) {
4400
		return;
4401
	}
4402

    
4403
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4404
	$realif = get_real_interface($interface);
4405
	$linklocal = find_interface_ipv6_ll($realif, true);
4406
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4407
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4408
	}
4409

    
4410
	$trackcfg = config_get_path("interfaces/{$wancfg['track6-interface']}");
4411
	if (!isset($trackcfg['enable'])) {
4412
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4413
		return;
4414
	}
4415

    
4416
	$type = $trackcfg['ipaddrv6'];
4417
	switch ($type) {
4418
		case "6to4":
4419
			if (g_get('debug')) {
4420
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4421
			}
4422
			interface_track6_6to4_configure($interface, $wancfg);
4423
			break;
4424
		case "6rd":
4425
			if (g_get('debug')) {
4426
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4427
			}
4428
			interface_track6_6rd_configure($interface, $wancfg);
4429
			break;
4430
		case "dhcp6":
4431
			if ($linkupevent == true) {
4432
				/*
4433
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4434
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4435
				 *
4436
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4437
				 */
4438
				$pidv6 = find_dhcp6c_process();
4439
				if ($pidv6) {
4440
					posix_kill($pidv6, SIGHUP);
4441
				}
4442
			}
4443
			break;
4444
	}
4445

    
4446
	if ($linkupevent == false && !is_platform_booting()) {
4447
		if (!function_exists('services_dhcpd_configure')) {
4448
			require_once("services.inc");
4449
		}
4450

    
4451
		/* restart dns servers (defering dhcpd reload) */
4452
		if (config_path_enabled('unbound')) {
4453
			services_unbound_configure(false, $interface);
4454
		}
4455
		if (config_path_enabled('dnsmasq')) {
4456
			services_dnsmasq_configure(false);
4457
		}
4458

    
4459
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4460
		services_dhcpd_configure("inet6");
4461
	}
4462

    
4463
	return 0;
4464
}
4465

    
4466
function interface_track6_6rd_configure($interface, $lancfg) {
4467
	global $interface_ipv6_arr_cache;
4468
	global $interface_snv6_arr_cache;
4469

    
4470
	if (!is_array($lancfg)) {
4471
		return;
4472
	}
4473

    
4474
	/* If the interface is not configured via another, exit */
4475
	if (empty($lancfg['track6-interface'])) {
4476
		return;
4477
	}
4478

    
4479
	$wancfg = config_get_path("interfaces/{$lancfg['track6-interface']}");
4480
	if (empty($wancfg)) {
4481
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4482
		return;
4483
	}
4484

    
4485
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4486
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4487
		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']));
4488
		return;
4489
	}
4490
	$hexwanv4 = return_hex_ipv4($ip4address);
4491

    
4492
	/* create the long prefix notation for math, save the prefix length */
4493
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4494
	$rd6prefixlen = $rd6prefix[1];
4495
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4496

    
4497
	/* binary presentation of the prefix for all 128 bits. */
4498
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4499

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

    
4505
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4506
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4507
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4508
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4509
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4510
	/* fill the rest out with zeros */
4511
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4512

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

    
4516
	$lanif = get_real_interface($interface);
4517
	$oip = find_interface_ipv6($lanif);
4518
	if (is_ipaddrv6($oip)) {
4519
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4520
	}
4521
	unset($interface_ipv6_arr_cache[$lanif]);
4522
	unset($interface_snv6_arr_cache[$lanif]);
4523
	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));
4524
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4525

    
4526
	return 0;
4527
}
4528

    
4529
function interface_track6_6to4_configure($interface, $lancfg) {
4530
	global $interface_ipv6_arr_cache;
4531
	global $interface_snv6_arr_cache;
4532

    
4533
	if (!is_array($lancfg)) {
4534
		return;
4535
	}
4536

    
4537
	/* If the interface is not configured via another, exit */
4538
	if (empty($lancfg['track6-interface'])) {
4539
		return;
4540
	}
4541

    
4542
	$wancfg = config_get_path("interfaces/{$lancfg['track6-interface']}");
4543
	if (empty($wancfg)) {
4544
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4545
		return;
4546
	}
4547

    
4548
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4549
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4550
		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']));
4551
		return;
4552
	}
4553
	$hexwanv4 = return_hex_ipv4($ip4address);
4554

    
4555
	/* create the long prefix notation for math, save the prefix length */
4556
	$sixto4prefix = "2002::";
4557
	$sixto4prefixlen = 16;
4558
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4559

    
4560
	/* binary presentation of the prefix for all 128 bits. */
4561
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4562

    
4563
	/* just save the left prefix length bits */
4564
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4565
	/* add the v4 address */
4566
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4567
	/* add the custom prefix id */
4568
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4569
	/* fill the rest out with zeros */
4570
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4571

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

    
4575
	$lanif = get_real_interface($interface);
4576
	$oip = find_interface_ipv6($lanif);
4577
	if (is_ipaddrv6($oip)) {
4578
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4579
	}
4580
	unset($interface_ipv6_arr_cache[$lanif]);
4581
	unset($interface_snv6_arr_cache[$lanif]);
4582
	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));
4583
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4584

    
4585
	return 0;
4586
}
4587

    
4588
function interface_6rd_configure($interface, $wancfg) {
4589
	global $g;
4590

    
4591
	/* because this is a tunnel interface we can only function
4592
	 *	with a public IPv4 address on the interface */
4593

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

    
4598
	if (!is_module_loaded('if_stf.ko')) {
4599
		mwexec('/sbin/kldload if_stf.ko');
4600
	}
4601

    
4602
	$wanif = get_real_interface($interface);
4603
	$ip4address = find_interface_ip($wanif);
4604
	if (!is_ipaddrv4($ip4address)) {
4605
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4606
		return false;
4607
	}
4608
	$hexwanv4 = return_hex_ipv4($ip4address);
4609

    
4610
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4611
		$wancfg['prefix-6rd-v4plen'] = 0;
4612
	}
4613

    
4614
	/* create the long prefix notation for math, save the prefix length */
4615
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4616
	$rd6prefixlen = $rd6prefix[1];
4617
	$brgw = explode('.', $wancfg['gateway-6rd']);
4618
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4619
	$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);
4620
	if (strlen($rd6brgw) < 128) {
4621
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4622
	}
4623
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4624
	unset($brgw);
4625
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4626

    
4627
	/* binary presentation of the prefix for all 128 bits. */
4628
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4629

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

    
4637
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4638
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4639

    
4640

    
4641
	/* XXX: need to extend to support variable prefix size for v4 */
4642
	$stfiface = "{$interface}_stf";
4643
	if (does_interface_exist($stfiface)) {
4644
		pfSense_interface_destroy($stfiface);
4645
	}
4646
	$tmpstfiface = pfSense_interface_create2("stf");
4647
	if (!is_string($tmpstfiface)) {
4648
		log_error(sprintf(gettext('Failed to configure interface %1$s: Could not create temporary interface %2$s'), $wanif, 'stf'));
4649
		return false;
4650
	}
4651
	pfSense_interface_rename($tmpstfiface, $stfiface);
4652
	pfSense_interface_flags($stfiface, IFF_LINK2);
4653
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4654
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4655
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4656
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4657
	}
4658
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4659
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4660
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4661
	} elseif ($parentmtu > 1300) {
4662
		set_interface_mtu($stfiface, $parentmtu - 20);
4663
	}
4664
	if (g_get('debug')) {
4665
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4666
	}
4667

    
4668
	/* write out a default router file */
4669
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4670
	unlink_if_exists("{$g['tmp_path']}/{$wanif}_routerv6.last");
4671
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4672

    
4673
	$ip4gateway = get_interface_gateway($interface);
4674
	if (is_ipaddrv4($ip4gateway)) {
4675
		route_add_or_change($wancfg['gateway-6rd'], $ip4gateway);
4676
	}
4677

    
4678
	/* configure dependent interfaces */
4679
	if (!is_platform_booting()) {
4680
		link_interface_to_track6($interface, "update");
4681
	}
4682

    
4683
	return 0;
4684
}
4685

    
4686
function interface_6to4_configure($interface, $wancfg) {
4687
	global $g;
4688

    
4689
	/* because this is a tunnel interface we can only function
4690
	 *	with a public IPv4 address on the interface */
4691

    
4692
	if (!is_array($wancfg)) {
4693
		return;
4694
	}
4695

    
4696
	$wanif = get_real_interface($interface);
4697
	$ip4address = find_interface_ip($wanif);
4698
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4699
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4700
		return false;
4701
	}
4702

    
4703
	/* create the long prefix notation for math, save the prefix length */
4704
	$stfprefixlen = 16;
4705
	$stfprefix = Net_IPv6::uncompress("2002::");
4706
	$stfarr = explode(":", $stfprefix);
4707
	$v4prefixlen = "0";
4708

    
4709
	/* we need the hex form of the interface IPv4 address */
4710
	$ip4arr = explode(".", $ip4address);
4711
	$hexwanv4 = "";
4712
	foreach ($ip4arr as $octet) {
4713
		$hexwanv4 .= sprintf("%02x", $octet);
4714
	}
4715

    
4716
	/* we need the hex form of the broker IPv4 address */
4717
	$ip4arr = explode(".", "192.88.99.1");
4718
	$hexbrv4 = "";
4719
	foreach ($ip4arr as $octet) {
4720
		$hexbrv4 .= sprintf("%02x", $octet);
4721
	}
4722

    
4723
	/* binary presentation of the prefix for all 128 bits. */
4724
	$stfprefixbin = "";
4725
	foreach ($stfarr as $element) {
4726
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4727
	}
4728
	/* just save the left prefix length bits */
4729
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4730

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

    
4735
	/* for the local subnet too. */
4736
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4737
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4738

    
4739
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4740
	$stfbrarr = array();
4741
	$stfbrbinarr = array();
4742
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4743
	foreach ($stfbrbinarr as $bin) {
4744
		$stfbrarr[] = dechex(bindec($bin));
4745
	}
4746
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4747

    
4748
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4749
	$stflanarr = array();
4750
	$stflanbinarr = array();
4751
	$stflanbinarr = str_split($stflanbin, 16);
4752
	foreach ($stflanbinarr as $bin) {
4753
		$stflanarr[] = dechex(bindec($bin));
4754
	}
4755
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4756
	$stflanarr[7] = 1;
4757

    
4758
	/* setup the stf interface */
4759
	if (!is_module_loaded("if_stf")) {
4760
		mwexec("/sbin/kldload if_stf.ko");
4761
	}
4762
	$stfiface = "{$interface}_stf";
4763
	if (does_interface_exist($stfiface)) {
4764
		pfSense_interface_destroy($stfiface);
4765
	}
4766
	$tmpstfiface = pfSense_interface_create2("stf");
4767
	if (!is_string($tmpstfiface)) {
4768
		log_error(sprintf(gettext('Failed to configure interface %1$s: Could not create temporary interface %2$s'), $wanif, 'stf'));
4769
		return;
4770
	}
4771
	pfSense_interface_rename($tmpstfiface, $stfiface);
4772
	pfSense_interface_flags($stfiface, IFF_LINK2);
4773
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4774

    
4775
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4776
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4777
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4778
	} elseif ($parentmtu > 1300) {
4779
		set_interface_mtu($stfiface, $parentmtu - 20);
4780
	}
4781
	if (g_get('debug')) {
4782
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4783
	}
4784

    
4785
	/* write out a default router file */
4786
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4787
	unlink_if_exists("{$g['tmp_path']}/{$wanif}_routerv6.last");
4788
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4789

    
4790
	$ip4gateway = get_interface_gateway($interface);
4791
	if (is_ipaddrv4($ip4gateway)) {
4792
		route_add_or_change("192.88.99.1", $ip4gateway);
4793
	}
4794

    
4795
	if (!is_platform_booting()) {
4796
		link_interface_to_track6($interface, "update");
4797
	}
4798

    
4799
	return 0;
4800
}
4801

    
4802
function interface_dhcpv6_configure($ifconf, $ifcfg, $destroy = false) {
4803
	global $g;
4804

    
4805
	$dhcp6cconf = "";
4806
	$id = "0";
4807
	$dhcp6cinterfaces = array();
4808
	$dhcp6cifs_descr = array();
4809
	$dhcp6crealifs = array();
4810
	$debugOption = "-d";
4811
	$noreleaseOption = "";
4812

    
4813
	if (!empty(config_get_path('system/global-v6duid'))) {
4814
		// Write the DUID file
4815
		if(!write_dhcp6_duid(config_get_path('system/global-v6duid'))) {
4816
		    log_error(gettext("Failed to write user DUID file!"));
4817
		}
4818
	}
4819

    
4820
	foreach (config_get_path('interfaces', []) as $interface => $wancfg) {
4821
		$wanif = get_real_interface($interface, "inet6");
4822

    
4823
		if (($ifconf == $interface) && $destroy) {
4824
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
4825
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh");
4826
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$wanif}_script.sh");
4827
			unlink_if_exists(g_get('vardb_path') . "/{$wanif}_cacheipv6");
4828
			continue;
4829
		}
4830

    
4831
		if (!isset($wancfg['enable']) || (($ifconf == $interface) && $destroy) ||
4832
		    (($wancfg['ipaddrv6'] != 'dhcp6') && ($wancfg['ipaddrv6'] != 'slaac'))) {
4833
			continue;
4834
		}
4835

    
4836
		$dhcp6cinterfaces[$interface] = $wancfg;
4837

    
4838
		if (config_path_enabled('system','dhcp6debug')) {
4839
			$debugOption = "-D";
4840
		}
4841
		if (config_path_enabled('system','dhcp6norelease')) {
4842
			$noreleaseOption = "-n";
4843
		}
4844

    
4845
		/* accept router advertisements for this interface                 */
4846
		/* Moved to early in the function as sometimes interface not ready */
4847
		/* RTSOLD fails as interface does not accept .....                 */
4848

    
4849
		log_error("Accept router advertisements on interface {$wanif} ");
4850
		mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4851

    
4852
		if ($wancfg['adv_dhcp6_config_file_override']) {
4853
			// DHCP6 Config File Override
4854
			$dhcp6cconf .= DHCP6_Config_File_Override($wancfg, $wanif);
4855
		} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4856
			// DHCP6 Config File Advanced
4857
			$dhcp6cconf .= DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4858
		} else {
4859
			// DHCP6 Config File Basic
4860
			$dhcp6cconf .= "interface {$wanif} {\n";
4861

    
4862
			/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4863
			if ($wancfg['ipaddrv6'] == "slaac") {
4864
				$dhcp6cconf .= "\tinformation-only;\n";
4865
				$dhcp6cconf .= "\trequest domain-name-servers;\n";
4866
				$dhcp6cconf .= "\trequest domain-name;\n";
4867
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4868
				$dhcp6cconf .= "};\n";
4869
			} else {
4870
				$trackiflist = array();
4871
				$iflist = link_interface_to_track6($interface);
4872
				foreach ($iflist as $ifname => $ifcfg) {
4873
					if (is_numeric($ifcfg['track6-prefix-id'])) {
4874
						$trackiflist[$ifname] = $ifcfg;
4875
					}
4876
				}
4877

    
4878
				/* skip address request if this is set */
4879
				if (!isset($wancfg['dhcp6prefixonly'])) {
4880
					$dhcp6cconf .= "\tsend ia-na {$id};\t# request stateful address\n";
4881
				}
4882
				if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4883
					$dhcp6cconf .= "\tsend ia-pd {$id};\t# request prefix delegation\n";
4884
				}
4885

    
4886
				$dhcp6cconf .= "\trequest domain-name-servers;\n";
4887
				$dhcp6cconf .= "\trequest domain-name;\n";
4888

    
4889
				/*
4890
				 * dhcp6c will run different scripts depending on
4891
				 * whether dhcpwithoutra is set or unset.
4892
				 */
4893
				if (isset($wancfg['dhcp6withoutra'])) {
4894
					$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4895
				} else {
4896
					$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4897
				}
4898
				$dhcp6cconf .= "};\n";
4899

    
4900
				if (!isset($wancfg['dhcp6prefixonly'])) {
4901
					$dhcp6cconf .= "id-assoc na {$id} { };\n";
4902
				}
4903

    
4904
				if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4905
					/* Setup the prefix delegation */
4906
					$dhcp6cconf .= "id-assoc pd {$id} {\n";
4907
					$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4908
					if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4909
						$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4910
					}
4911
					foreach ($trackiflist as $friendly => $ifcfg) {
4912
						if (g_get('debug')) {
4913
							log_error("setting up $interface - {$ifcfg['track6-prefix-id']}");
4914
						}
4915
						$realif = get_real_interface($friendly);
4916
						$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4917
						$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4918
						$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4919
						$dhcp6cconf .= "\t};\n";
4920
					}
4921
					unset($preflen, $iflist, $ifcfg, $ifname);
4922
					$dhcp6cconf .= "};\n\n";
4923
				}
4924
				unset($trackiflist);
4925
			}
4926
			$id++;
4927
		}
4928

    
4929
		/*************** Script Debug Logging ***************************
4930
		Both dhcp6 scripts now have a logging message built in.
4931
		These logging messages ONLY appear if dhcp6c debug logging is set.
4932
		The logging messages appear in the dhcp section of the logs,
4933
		not in system.
4934

    
4935
		These scripts now also take advantage of the REASON= env vars
4936
		supplied by dhcp6c.
4937
		****************************************************************/
4938

    
4939
		/* Script create for dhcp6withoutRA mode */
4940
		/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
4941
		$dhcp6cscriptwithoutra = "#!/bin/sh\n";
4942
		$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4943
		$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4944
		$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4945
		$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
4946
		// Need to pass params to  the final script
4947
		$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4948
		$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4949
		$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
4950
		$dhcp6cscriptwithoutra .= "case \$REASON in\n";
4951
		$dhcp6cscriptwithoutra .= "REQUEST)\n";
4952
		$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -A {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
4953
		if ($debugOption == '-D') {
4954
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rtsold\"\n";
4955
		}
4956
		$dhcp6cscriptwithoutra .= ";;\n";
4957
		$dhcp6cscriptwithoutra .= "REBIND)\n";
4958
		if ($debugOption == '-D') {
4959
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4960
		}
4961
		$dhcp6cscriptwithoutra .= ";;\n";
4962
		if (isset($wancfg['dhcp6norelease'])) {
4963
			$dhcp6cscriptwithoutra .= "EXIT)\n";
4964
		} else {
4965
			$dhcp6cscriptwithoutra .= "RELEASE)\n";
4966
		}
4967
		if ($debugOption == '-D') {
4968
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4969
		}
4970
		$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
4971
		$dhcp6cscriptwithoutra .= ";;\n";
4972
		$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
4973
		if ($debugOption == '-D') {
4974
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
4975
		}
4976
		$dhcp6cscriptwithoutra .= "esac\n";
4977
		if (!@file_put_contents(
4978
		    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
4979
		    $dhcp6cscriptwithoutra)) {
4980
			printf("Error: cannot open " .
4981
			    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
4982
			    "interface_dhcpv6_configure() for writing.\n");
4983
			unset($dhcp6cscriptwithoutra);
4984
			return 1;
4985
		}
4986

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

    
4989
		/*
4990
		 * Dual mode wan_dhcp6c script with variations depending on node
4991
		 * dhcp6 will run the wan ipv6 configure
4992
		 */
4993
		$dhcp6cscript  = "#!/bin/sh\n";
4994
		$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
4995
		if (!isset($wancfg['dhcp6withoutra'])) {
4996
			$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
4997
			$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
4998
			$dhcp6cscript .= "case \$REASON in\n";
4999
			$dhcp6cscript .= "REBIND)\n";
5000
			if ($debugOption == '-D') {
5001
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
5002
			}
5003
			$dhcp6cscript .= ";;\n";
5004
			$dhcp6cscript .= "REQUEST|";
5005
			if (isset($wancfg['dhcp6norelease'])) {
5006
				$dhcp6cscript .= "EXIT)\n";
5007
			} else {
5008
				$dhcp6cscript .= "RELEASE)\n";
5009
			}
5010
			if ($debugOption == '-D') {
5011
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c RELEASE, REQUEST or EXIT on {$wanif} running rc.newwanipv6\"\n";
5012
			}
5013
			$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5014
			$dhcp6cscript .= ";;\n";
5015
			$dhcp6cscript .= "RENEW|INFO)\n";
5016
			if ($debugOption == '-D') {
5017
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5018
			}
5019
			$dhcp6cscript .= "esac\n";
5020
			$rtsold_ra_ifs[] = $wanif;
5021
		} else {
5022
			// Need to get the parameters from the dhcp6cwithoutRA run
5023
			$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
5024
			$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
5025
			$dhcp6cscript .= "/bin/sleep 1\n";
5026
			$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5027
		}
5028

    
5029
		/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5030
		if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
5031
			printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
5032
			unset($dhcp6cscript);
5033
			return 1;
5034
		}
5035
		unset($dhcp6cscript);
5036
		@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
5037
	}
5038

    
5039
	if (!empty($dhcp6cinterfaces)) {
5040
		/* wide-dhcp6c works for now. */
5041
		if (!@file_put_contents("{$g['varetc_path']}/dhcp6c.conf", $dhcp6cconf)) {
5042
			printf("Error: cannot open dhcp6c.conf in interface_dhcpv6_configure() for writing.\n");
5043
			return 1;
5044
		}
5045
		foreach ($dhcp6cinterfaces as $interface => $wancfg) {
5046
			$dhcp6cifs_descr[] = $interface . '(' . $wancfg['if'] . ')';
5047
			$dhcp6crealifs[] = $wancfg['if'];
5048
		}
5049
		$dhcp6cdescr = implode(',', $dhcp6cifs_descr);
5050
		$dhcp6cifs = implode(' ', $dhcp6crealifs);
5051
		foreach ($dhcp6cinterfaces as $interface => $wancfg) {
5052
			$wanif = get_real_interface($interface, "inet6");
5053

    
5054
			$rtsoldscript_header = <<<EOD
5055
#!/bin/sh
5056
# This shell script launches dhcp6c and configured gateways for this interface.
5057
if [ -n "\$2" ]; then
5058
	if [ -n "$(echo \$2 | /usr/bin/grep '^fe80')" ]; then
5059
		echo \$2\%{$wanif} > {$g['tmp_path']}/{$wanif}_routerv6
5060
		/bin/rm -f {$g['tmp_path']}/{$wanif}_routerv6.last
5061
		echo \$2\%{$wanif} > {$g['tmp_path']}/{$wanif}_defaultgwv6
5062
	else
5063
		echo \$2 > {$g['tmp_path']}/{$wanif}_routerv6
5064
		/bin/rm -f {$g['tmp_path']}/{$wanif}_routerv6.last
5065
		echo \$2 > {$g['tmp_path']}/{$wanif}_defaultgwv6
5066
	fi
5067
	/usr/bin/logger -t rtsold "Received RA specifying route \$2 for interface {$interface}({$wanif})"
5068
fi
5069

    
5070
EOD;
5071

    
5072
			/* non ipoe Process */
5073
			$rtsoldscript = $rtsoldscript_header;
5074
			if (!isset($wancfg['dhcp6withoutra'])) {
5075
				/*
5076
				 * We only want this script to run once, and if it runs twice
5077
				 * then do not launch dhcp6c again, this only happens if
5078
				 * dhcpwithoutra is not set.
5079
				 *
5080
				 * Check for a lock file, trying to prevent multiple instances
5081
				 * of dhcp6c being launched
5082
				 */
5083
				$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_lock ]; then\n";
5084
				/*
5085
				 * Create the lock file, trying to prevent multiple instances
5086
				 * of dhcp6c being launched
5087
				 */
5088
				$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_lock\n";
5089
				$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c.pid ]; then\n";
5090
				$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c.pid\n";
5091
				$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c.pid\n";
5092
				$rtsoldscript .= "\t\t/bin/sleep 1\n";
5093
				$rtsoldscript .= "\tfi\n";
5094
				$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
5095
				    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c.conf " .
5096
				    "-p {$g['varrun_path']}/dhcp6c.pid {$dhcp6cifs}\n";
5097
				$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interfaces {$dhcp6cdescr}\"\n";
5098
				$rtsoldscript .= "else\n";
5099
				$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
5100
				$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c.pid\")\n";
5101
				$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
5102
				$rtsoldscript .= "fi\n";
5103
			} else {
5104
				/*
5105
				 * The script needs to run in dhcp6withoutra mode as RA may
5106
				 * not have been received, or there can be a delay with
5107
				 * certain ISPs
5108
				 */
5109
				$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
5110
				$rtsoldscript .= "/bin/sleep 1\n";
5111
			}
5112

    
5113
			/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5114
			if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
5115
				printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
5116
				return 1;
5117
			}
5118
			unset($rtsoldscript);
5119
			@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
5120
		}
5121

    
5122
		$realif = get_real_interface($ifconf, "inet6");
5123
		if (isvalidpid("{$g['varrun_path']}/rtsold_{$realif}.pid")) {
5124
			killbypid("{$g['varrun_path']}/rtsold_{$realif}.pid");
5125
			log_error("Killing running rtsold process");
5126
			sleep(2);
5127
		}
5128

    
5129
		if (file_exists("{$g['tmp_path']}/dhcp6c_ifs")) {
5130
			$dhcp6crealifs_run = unserialize_data(file_get_contents("{$g['tmp_path']}/dhcp6c_ifs"), []);
5131
		} else {
5132
			$dhcp6crealifs_run = array();
5133
		}
5134

    
5135
		if (($dhcp6crealifs != $dhcp6crealifs_run) || $destroy) {
5136
			kill_dhcp6client_process(false);
5137
			run_dhcp6client_process($dhcp6crealifs, $debugOption, $noreleaseOption);
5138
			file_put_contents("{$g['tmp_path']}/dhcp6c_ifs", serialize($dhcp6crealifs));
5139
			$dhcp6c_restarted = true;
5140
			if ($destroy) {
5141
				$track6 = link_interface_to_track6($ifconf);
5142
				if (is_array($track6) && !empty($track6)) {
5143
					/* remove stale track interfaces IP */
5144
					foreach (array_keys($track6) as $tr6if) {
5145
						interface_reconfigure($tr6if, true);
5146
					}
5147
				}
5148
			}
5149
		}
5150

    
5151
		if (isset($ifcfg['dhcp6withoutra']) && !$dhcp6c_restarted) {
5152
			/*
5153
			 * Start dhcp6c here if we don't want to wait for ra - calls
5154
			 * separate function
5155
			 *
5156
			 * In this mode dhcp6c launches rtsold via its script. RTSOLD
5157
			 * will then run the configure on receipt of the RA.
5158
			 *
5159
			 * Already started. interface_dhcpv6_configure() appears to get
5160
			 * called multiple times.
5161
			 *
5162
			 * Taking the interface down or releasing will kill the client.
5163
			 */
5164

    
5165
			/*
5166
			 * If the interface is being brought up, wait for the
5167
			 * interface to configure accept RA before launching.
5168
			 * Otherwise it is not ready to accept and will fail.
5169
			 */
5170
			sleep(3);
5171
			if (file_exists("/tmp/dhcp6c_lock")) {
5172
				reset_dhcp6client_process();
5173
			}
5174
		} elseif (!$destroy) {
5175
			/*
5176
			 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
5177
			 * ( it does not background, it exits! ) It will launch dhcp6c
5178
			 * if dhcpwihtoutra is not set
5179
			 */
5180
			log_error("Starting rtsold process on {$ifconf}({$realif})");
5181
			sleep(2);
5182
			mwexec("/usr/sbin/rtsold -1 " .
5183
			    "-p {$g['varrun_path']}/rtsold_{$realif}.pid " .
5184
			    "-A {$g['varetc_path']}/rtsold_{$realif}_script.sh " .
5185
			    $realif);
5186
		}
5187
	} else {
5188
		kill_dhcp6client_process(true);
5189
		unlink_if_exists("{$g['varetc_path']}/dhcp6c.conf");
5190
		unlink_if_exists("{$g['tmp_path']}/dhcp6c_ifs");
5191
	}
5192

    
5193
	/*
5194
	 * NOTE: will be called from rtsold invoked script
5195
	 * link_interface_to_track6($interface, "update");
5196
	 */
5197

    
5198
	return 0;
5199
}
5200

    
5201
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5202
	global $g;
5203

    
5204
	$send_options = "";
5205
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
5206
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
5207
		foreach ($options as $option) {
5208
			$send_options .= "\tsend " . trim($option) . ";\n";
5209
		}
5210
	}
5211

    
5212
	$request_options = "";
5213
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5214
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5215
		foreach ($options as $option) {
5216
			$request_options .= "\trequest " . trim($option) . ";\n";
5217
		}
5218
	}
5219

    
5220
	$information_only = "";
5221
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5222
		$information_only = "\tinformation-only;\n";
5223
	}
5224

    
5225
	if (isset($wancfg['dhcp6withoutra'])) {
5226
		$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\";\n";
5227
	} else {
5228
		$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5229
	}
5230
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5231
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5232
	}
5233

    
5234
	$interface_statement  = "interface";
5235
	$interface_statement .= " {$wanif}";
5236
	$interface_statement .= " {\n";
5237
	$interface_statement .= "$send_options";
5238
	$interface_statement .= "$request_options";
5239
	$interface_statement .= "$information_only";
5240
	$interface_statement .= "$script";
5241
	$interface_statement .= "};\n";
5242

    
5243
	$id_assoc_statement_address = "";
5244
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5245
		$id_assoc_statement_address .= "id-assoc";
5246
		$id_assoc_statement_address .= " na";
5247
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5248
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5249
		}
5250
		$id_assoc_statement_address .= " { ";
5251

    
5252
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5253
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5254
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5255
			$id_assoc_statement_address .= "\n\taddress";
5256
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5257
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5258
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5259
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5260
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5261
			}
5262
			$id_assoc_statement_address .= ";\n";
5263
		}
5264

    
5265
		$id_assoc_statement_address .= "};\n";
5266
	}
5267

    
5268
	$id_assoc_statement_prefix = "";
5269
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5270
		$id_assoc_statement_prefix .= "id-assoc";
5271
		$id_assoc_statement_prefix .= " pd";
5272
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5273
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5274
		}
5275
		$id_assoc_statement_prefix .= " { ";
5276

    
5277
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5278
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5279
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5280
			$id_assoc_statement_prefix .= "\n\tprefix";
5281
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5282
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5283
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5284
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5285
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5286
			}
5287
			$id_assoc_statement_prefix .= ";";
5288
		}
5289

    
5290
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
5291
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
5292
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
5293
			$id_assoc_statement_prefix .= " {$realif}";
5294
			$id_assoc_statement_prefix .= " {\n";
5295
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
5296
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
5297
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
5298
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
5299
			}
5300
			$id_assoc_statement_prefix .= "\t};";
5301
		}
5302

    
5303
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5304
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5305
			$id_assoc_statement_prefix .= "\n";
5306
		}
5307

    
5308
		$id_assoc_statement_prefix .= "};\n";
5309
	}
5310

    
5311
	$authentication_statement = "";
5312
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
5313
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
5314
		$authentication_statement .= "authentication";
5315
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
5316
		$authentication_statement .= " {\n";
5317
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
5318
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
5319
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
5320
		}
5321
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
5322
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
5323
		}
5324
		$authentication_statement .= "};\n";
5325
	}
5326

    
5327
	$key_info_statement = "";
5328
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5329
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5330
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5331
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5332
		$key_info_statement .= "keyinfo";
5333
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5334
		$key_info_statement .= " {\n";
5335
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5336
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5337
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5338
		if (preg_match("/((([0-9]{4}-)?[0-9]{2}[0-9]{2} )?[0-9]{2}:[0-9]{2})||(forever)/", $wancfg['adv_dhcp6_key_info_statement_expire'])) {
5339
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5340
		}
5341
		$key_info_statement .= "};\n";
5342
	}
5343

    
5344
	$dhcp6cconf  = $interface_statement;
5345
	$dhcp6cconf .= $id_assoc_statement_address;
5346
	$dhcp6cconf .= $id_assoc_statement_prefix;
5347
	$dhcp6cconf .= $authentication_statement;
5348
	$dhcp6cconf .= $key_info_statement;
5349

    
5350
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5351

    
5352
	return $dhcp6cconf;
5353
}
5354

    
5355

    
5356
function DHCP6_Config_File_Override($wancfg, $wanif) {
5357

    
5358
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5359

    
5360
	if ($dhcp6cconf === false) {
5361
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5362
		return '';
5363
	} else {
5364
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5365
	}
5366
}
5367

    
5368

    
5369
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5370

    
5371
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5372

    
5373
	return $dhcp6cconf;
5374
}
5375

    
5376

    
5377
function interface_dhcp_configure($interface) {
5378
	global $g, $vlanprio_values;
5379

    
5380
	$ifcfg = config_get_path("interfaces/{$interface}");
5381
	if (empty($ifcfg)) {
5382
		$ifcfg = array();
5383
	}
5384

    
5385
	$dhclientconf_vlantag = "";
5386
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5387
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5388
	}
5389

    
5390
	/* generate dhclient_wan.conf */
5391
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5392
	if (!$fd) {
5393
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5394
		return 1;
5395
	}
5396

    
5397
	if ($ifcfg['dhcphostname']) {
5398
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5399
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5400
	} else {
5401
		$dhclientconf_hostname = "";
5402
	}
5403

    
5404
	$realif = get_real_interface($interface);
5405
	if (empty($realif)) {
5406
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5407
		return 0;
5408
	}
5409
	$dhclientconf = "";
5410

    
5411
	$dhclientconf .= <<<EOD
5412
interface "{$realif}" {
5413
	supersede interface-mtu 0;
5414
	timeout 60;
5415
	retry 15;
5416
	select-timeout 0;
5417
	initial-interval 1;
5418
	{$dhclientconf_vlantag}
5419
	{$dhclientconf_hostname}
5420
	script "/usr/local/sbin/pfSense-dhclient-script";
5421
EOD;
5422

    
5423
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5424
		$dhclientconf .= <<<EOD
5425

    
5426
	reject {$ifcfg['dhcprejectfrom']};
5427
EOD;
5428
	}
5429
	$dhclientconf .= <<<EOD
5430

    
5431
}
5432

    
5433
EOD;
5434

    
5435
	// DHCP Config File Advanced
5436
	if ($ifcfg['adv_dhcp_config_advanced']) {
5437
		$dhclientconf = DHCP_Config_File_Advanced($ifcfg, $realif);
5438
	}
5439

    
5440
	if (is_ipaddr($ifcfg['alias-address'])) {
5441
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5442
		$dhclientconf .= <<<EOD
5443
alias {
5444
	interface "{$realif}";
5445
	fixed-address {$ifcfg['alias-address']};
5446
	option subnet-mask {$subnetmask};
5447
}
5448

    
5449
EOD;
5450
	}
5451

    
5452
	// DHCP Config File Override
5453
	if ($ifcfg['adv_dhcp_config_file_override']) {
5454
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5455
	}
5456

    
5457
	fwrite($fd, $dhclientconf);
5458
	fclose($fd);
5459

    
5460
	/* bring wan interface up before starting dhclient */
5461
	if ($realif) {
5462
		interfaces_bring_up($realif);
5463
	}
5464

    
5465
	/* Make sure dhclient is not running */
5466
	kill_dhclient_process($realif);
5467

    
5468
	/* fire up dhclient */
5469
	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");
5470

    
5471
	return 0;
5472
}
5473

    
5474
function DHCP_Config_File_Advanced($ifcfg, $realif) {
5475

    
5476
	$hostname = "";
5477
	if ($ifcfg['dhcphostname'] != '') {
5478
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5479
	}
5480

    
5481
	/* DHCP Protocol Timings */
5482
	$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");
5483
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5484
		$pt_variable = "{$Protocol_Timing}";
5485
		${$pt_variable} = "";
5486
		if ($ifcfg[$Protocol_Timing] != "") {
5487
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5488
		}
5489
	}
5490

    
5491
	$send_options = "";
5492
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5493
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5494
		foreach ($options as $option) {
5495
			$send_options .= "\tsend " . trim($option) . ";\n";
5496
		}
5497
	}
5498

    
5499
	$request_options = "";
5500
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5501
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5502
	}
5503

    
5504
	$required_options = "";
5505
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5506
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5507
	}
5508

    
5509
	$option_modifiers = "";
5510
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5511
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5512
		foreach ($modifiers as $modifier) {
5513
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5514
		}
5515
	}
5516

    
5517
	$dhclientconf  = "interface \"{$realif}\" {\n";
5518
	$dhclientconf .= "\n";
5519
	$dhclientconf .= "\tsupersede interface-mtu 0;\n";
5520
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5521
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5522
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5523
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5524
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5525
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5526
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5527
	$dhclientconf .= "\n";
5528
	$dhclientconf .= "# DHCP Protocol Options\n";
5529
	$dhclientconf .= "{$hostname}";
5530
	$dhclientconf .= "{$send_options}";
5531
	$dhclientconf .= "{$request_options}";
5532
	$dhclientconf .= "{$required_options}";
5533
	$dhclientconf .= "{$option_modifiers}";
5534
	$dhclientconf .= "\n";
5535
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5536
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5537
	}
5538
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5539
	$dhclientconf .= "}\n";
5540

    
5541
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5542

    
5543
	return $dhclientconf;
5544
}
5545

    
5546
function DHCP_Config_Option_Split($option_string) {
5547
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5548
	return $matches ? $matches[0] : [];
5549
}
5550

    
5551
function DHCP_Config_File_Override($ifcfg, $realif) {
5552

    
5553
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5554

    
5555
	if ($dhclientconf === false) {
5556
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5557
		return '';
5558
	} else {
5559
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5560
	}
5561
}
5562

    
5563

    
5564
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5565

    
5566
	/* Apply Interface Substitutions */
5567
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5568

    
5569
	/* Apply Hostname Substitutions */
5570
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5571

    
5572
	/* Arrays of MAC Address Types, Cases, Delimiters */
5573
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5574
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5575
	$various_mac_cases      = array("U", "L");
5576
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5577

    
5578
	/* Apply MAC Address Substitutions */
5579
	foreach ($various_mac_types as $various_mac_type) {
5580
		foreach ($various_mac_cases as $various_mac_case) {
5581
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5582

    
5583
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5584
				if ($res !== false) {
5585

    
5586
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5587
					if ("$various_mac_case" == "U") {
5588
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5589
					}
5590
					if ("$various_mac_case" == "L") {
5591
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5592
					}
5593

    
5594
					if ("$various_mac_type" == "mac_addr_hex") {
5595
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5596
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5597
						$dhcpclientconf_mac_hex = "";
5598
						$delimiter = "";
5599
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5600
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5601
							$delimiter = ":";
5602
						}
5603
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5604
					}
5605

    
5606
					/* MAC Address Delimiter Substitutions */
5607
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5608

    
5609
					/* Apply MAC Address Substitutions */
5610
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5611
				}
5612
			}
5613
		}
5614
	}
5615

    
5616
	return $dhclientconf;
5617
}
5618

    
5619
function interfaces_group_setup() {
5620
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $groupar) {
5621
		interface_group_setup($groupar);
5622
	}
5623

    
5624
	return;
5625
}
5626

    
5627
function interface_group_setup(&$groupname /* The parameter is an array */) {
5628
	if (!is_array($groupname)) {
5629
		return;
5630
	}
5631
	$members = explode(" ", $groupname['members']);
5632
	foreach ($members as $ifs) {
5633
		$realif = get_real_interface($ifs);
5634
		if ($realif && does_interface_exist($realif)) {
5635
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5636
		}
5637
	}
5638

    
5639
	return;
5640
}
5641

    
5642
function is_interface_group($if) {
5643
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $groupentry) {
5644
		if ($groupentry['ifname'] === $if) {
5645
			return true;
5646
		}
5647
	}
5648

    
5649
	return false;
5650
}
5651

    
5652
function interface_group_add_member($interface, $groupname) {
5653
	$interface = get_real_interface($interface);
5654
	if (does_interface_exist($interface)) {
5655
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5656
	}
5657
}
5658

    
5659
/* COMPAT Function */
5660
function convert_friendly_interface_to_real_interface_name($interface) {
5661
	return get_real_interface($interface);
5662
}
5663

    
5664
/* COMPAT Function */
5665
function get_real_wan_interface($interface = "wan") {
5666
	return get_real_interface($interface);
5667
}
5668

    
5669
/* COMPAT Function */
5670
function get_current_wan_address($interface = "wan") {
5671
	return get_interface_ip($interface);
5672
}
5673

    
5674
/*
5675
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5676
 */
5677
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5678

    
5679
	/* XXX: For speed reasons reference directly the interface array */
5680
	config_init_path('interfaces');
5681
	$ifdescrs = config_get_path('interfaces', []);
5682
	//$ifdescrs = get_configured_interface_list(true);
5683

    
5684
	foreach ($ifdescrs as $if => $ifname) {
5685
		if ($if == $interface || $ifname['if'] == $interface) {
5686
			return $if;
5687
		}
5688

    
5689
		if (get_real_interface($if) == $interface) {
5690
			return $if;
5691
		}
5692

    
5693
		if ($checkparent == false) {
5694
			continue;
5695
		}
5696

    
5697
		$int = get_parent_interface($if, true);
5698
		if (is_array($int)) {
5699
			foreach ($int as $iface) {
5700
				if ($iface == $interface) {
5701
					return $if;
5702
				}
5703
			}
5704
		}
5705
	}
5706

    
5707
	if ($interface == "enc0") {
5708
		return 'IPsec';
5709
	}
5710
}
5711

    
5712
/* attempt to resolve interface to friendly descr */
5713
function convert_friendly_interface_to_friendly_descr($interface) {
5714

    
5715
	$iface = config_get_path("interfaces/{$interface}");
5716
	switch ($interface) {
5717
		case "l2tp":
5718
			$ifdesc = "L2TP";
5719
			break;
5720
		case "pptp":
5721
			$ifdesc = "PPTP";
5722
			break;
5723
		case "pppoe":
5724
			$ifdesc = "PPPoE";
5725
			break;
5726
		case "openvpn":
5727
			$ifdesc = "OpenVPN";
5728
			break;
5729
		case "lo0":
5730
			$ifdesc = "Loopback";
5731
			break;
5732
		case "enc0":
5733
		case "ipsec":
5734
		case "IPsec":
5735
			$ifdesc = "IPsec";
5736
			break;
5737
		default:
5738
			if ($iface) {
5739
				if (empty($iface['descr'])) {
5740
					$ifdesc = strtoupper($interface);
5741
				} else {
5742
					$ifdesc = strtoupper($iface['descr']);
5743
				}
5744
				break;
5745
			} elseif (substr($interface, 0, 4) == '_vip') {
5746
				foreach (config_get_path('virtualip/vip', []) as $vip) {
5747
					if (($vip['mode'] == "carp") || ($vip['mode'] == "ipalias")) {
5748
						if ($interface == "_vip{$vip['uniqid']}") {
5749
							$descr = $vip['subnet'];
5750
							if (!empty($vip['vhid'])) {
5751
								$descr .= " (vhid {$vip['vhid']})";
5752
							}
5753
							if (!empty($vip['descr'])) {
5754
								$descr .= " - " .$vip['descr'];
5755
							}
5756
							return $descr;
5757
						}
5758
					}
5759
				}
5760
			} elseif (substr($interface, 0, 5) == '_lloc') {
5761
				return get_interface_linklocal($interface);
5762
			} else {
5763
				foreach (config_get_path('ifgroups/ifgroupentry', []) as $ifgen) {
5764
					if ($ifgen['ifname'] === $interface) {
5765
						return $ifgen['ifname'];
5766
					}
5767
				}
5768

    
5769
				/* if list */
5770
				$ifdescrs = get_configured_interface_with_descr(true);
5771
				foreach ($ifdescrs as $if => $ifname) {
5772
					if ($if == $interface || $ifname == $interface) {
5773
						return $ifname;
5774
					}
5775
				}
5776
			}
5777
			break;
5778
	}
5779

    
5780
	return $ifdesc;
5781
}
5782

    
5783
function convert_real_interface_to_friendly_descr($interface) {
5784

    
5785
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5786

    
5787
	if (!empty($ifdesc)) {
5788
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5789
	}
5790

    
5791
	return $interface;
5792
}
5793

    
5794
/*
5795
 *  get_parent_interface($interface):
5796
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5797
 *				or virtual interface (i.e. vlan)
5798
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5799
 *			-- returns $interface passed in if $interface parent is not found
5800
 *			-- returns empty array if an invalid interface is passed
5801
 *	(Only handles ppps and vlans now.)
5802
 */
5803
function get_parent_interface($interface, $avoidrecurse = false) {
5804
	$parents = array();
5805
	//Check that we got a valid interface passed
5806
	$realif = get_real_interface($interface);
5807
	if ($realif == NULL) {
5808
		return $parents;
5809
	}
5810

    
5811
	// If we got a real interface, find it's friendly assigned name
5812
	if ($interface == $realif && $avoidrecurse == false) {
5813
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5814
	}
5815

    
5816
	$iface = config_get_path("interfaces/{$interface}");
5817
	if (!empty($interface) && $iface) {
5818
		$ifcfg = $iface;
5819
		switch ($ifcfg['ipaddr']) {
5820
			case "ppp":
5821
			case "pppoe":
5822
			case "pptp":
5823
			case "l2tp":
5824
				if (empty($parents)) {
5825
					foreach (config_get_path('ppps/ppp', []) as $ppp) {
5826
						if ($ifcfg['if'] == $ppp['if']) {
5827
							$ports = explode(',', $ppp['ports']);
5828
							foreach ($ports as $pid => $parent_if) {
5829
								$parents[$pid] = get_real_interface($parent_if);
5830
							}
5831
							break;
5832
						}
5833
					}
5834
				}
5835
				break;
5836
			case "dhcp":
5837
			case "static":
5838
			default:
5839
				// Handle _vlans
5840
				$vlan = interface_is_vlan($ifcfg['if']);
5841
				if ($vlan != NULL) {
5842
					$parents[0] = $vlan['if'];
5843
				}
5844
				break;
5845
		}
5846
	}
5847

    
5848
	if (empty($parents)) {
5849
		// Handle _vlans not assigned to an interface
5850
		$vlan = interface_is_vlan($realif);
5851
		if ($vlan != NULL) {
5852
			$parents[0] = $vlan['if'];
5853
		}
5854
	}
5855

    
5856
	if (empty($parents)) {
5857
		/* Handle LAGGs. */
5858
		$lagg = interface_is_type($realif, 'lagg');
5859
		if ($lagg != NULL && isset($lagg['members'])) {
5860
			$parents = explode(",", $lagg['members']);
5861
		}
5862
	}
5863

    
5864
	if (empty($parents)) {
5865
		$parents[0] = $realif;
5866
	}
5867

    
5868
	return $parents;
5869
}
5870

    
5871
/*
5872
 *  get_parent_physical_interface($interface):
5873
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5874
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5875
 */
5876
function get_parent_physical_interface($interface) {
5877

    
5878
	$realif = get_parent_interface($interface);
5879

    
5880
	if (substr($realif[0], 0, 4) == "lagg") {
5881
		foreach (config_get_path('laggs/lagg', []) as $lagg) {
5882
			if ($realif[0] == $lagg['laggif']) {
5883
				return explode(",", $lagg['members']);
5884
			}
5885
		}
5886
	} else {
5887
		return $realif;
5888
	}
5889
}
5890

    
5891
function interface_is_wireless_clone($wlif) {
5892
	if (!stristr($wlif, "_wlan")) {
5893
		return false;
5894
	} else {
5895
		return true;
5896
	}
5897
}
5898

    
5899
function interface_get_wireless_base($wlif) {
5900
	if (!stristr($wlif, "_wlan")) {
5901
		return $wlif;
5902
	} else {
5903
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5904
	}
5905
}
5906

    
5907
function interface_get_wireless_clone($wlif) {
5908
	if (!stristr($wlif, "_wlan")) {
5909
		return $wlif . "_wlan0";
5910
	} else {
5911
		return $wlif;
5912
	}
5913
}
5914

    
5915
function interface_list_wireless() {
5916
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5917

    
5918
	$result = array();
5919
	foreach ($portlist as $port) {
5920
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5921
			continue;
5922
		}
5923

    
5924
		$desc = $port . " ( " . get_single_sysctl(
5925
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5926

    
5927
		$result[] = array(
5928
		    "if" => $port,
5929
		    "descr" => $desc
5930
		);
5931
	}
5932

    
5933
	return $result;
5934
}
5935

    
5936
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = false) {
5937
	global $g;
5938

    
5939
	$wanif = NULL;
5940

    
5941
	switch ($interface) {
5942
		case "l2tp":
5943
			$wanif = "l2tp";
5944
			break;
5945
		case "pptp":
5946
			$wanif = "pptp";
5947
			break;
5948
		case "pppoe":
5949
			$wanif = "pppoe";
5950
			break;
5951
		case "openvpn":
5952
			$wanif = "openvpn";
5953
			break;
5954
		case "IPsec":
5955
		case "ipsec":
5956
		case "enc0":
5957
			$wanif = "enc0";
5958
			break;
5959
		case "ppp":
5960
			$wanif = "ppp";
5961
			break;
5962
		default:
5963
			if (substr($interface, 0, 4) == '_vip') {
5964
				$wanif = get_configured_vip_interface($interface);
5965
				if (!empty($wanif)) {
5966
					$wanif = get_real_interface($wanif);
5967
				}
5968
				break;
5969
			} elseif (substr($interface, 0, 5) == '_lloc') {
5970
				$interface = substr($interface, 5);
5971
			} elseif (interface_is_vlan($interface) != NULL ||
5972
			    does_interface_exist($interface, $flush)) {
5973
				/*
5974
				 * If a real interface was already passed simply
5975
				 * pass the real interface back.  This encourages
5976
				 * the usage of this function in more cases so that
5977
				 * we can combine logic for more flexibility.
5978
				 */
5979
				$wanif = $interface;
5980
				break;
5981
			}
5982

    
5983
			$cfg = config_get_path("interfaces/{$interface}");
5984
			if (empty($cfg))
5985
				break;
5986

    
5987
			if ($family == "inet6") {
5988
				switch ($cfg['ipaddrv6']) {
5989
					case "6rd":
5990
					case "6to4":
5991
						$wanif = "{$interface}_stf";
5992
						break;
5993
					case 'pppoe':
5994
					case 'ppp':
5995
					case 'l2tp':
5996
					case 'pptp':
5997
						if (is_array($cfg['wireless']) || preg_match(g_get('wireless_regex'), $cfg['if'])) {
5998
							$wanif = interface_get_wireless_clone($cfg['if']);
5999
						} else {
6000
							$wanif = $cfg['if'];
6001
						}
6002
						break;
6003
					default:
6004
						switch ($cfg['ipaddr']) {
6005
							case 'pppoe':
6006
							case 'ppp':
6007
							case 'l2tp':
6008
							case 'pptp':
6009
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
6010
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) ||
6011
								    isset($cfg['ipv6usev4iface']) || isset($cfg['slaacusev4iface'])) {
6012
									$wanif = $cfg['if'];
6013
								} else {
6014
									$parents = get_parent_interface($interface);
6015
									if (!empty($parents[0])) {
6016
										$wanif = $parents[0];
6017
									} else {
6018
										$wanif = $cfg['if'];
6019
									}
6020
								}
6021
								break;
6022
							default:
6023
								if (is_array($cfg['wireless']) || preg_match(g_get('wireless_regex'), $cfg['if'])) {
6024
									$wanif = interface_get_wireless_clone($cfg['if']);
6025
								} else {
6026
									$wanif = $cfg['if'];
6027
								}
6028
								break;
6029
						}
6030
						break;
6031
				}
6032
			} else {
6033
				// Wireless cloned NIC support (FreeBSD 8+)
6034
				// interface name format: $parentnic_wlanparentnic#
6035
				// example: ath0_wlan0
6036
				if (is_array($cfg['wireless']) || preg_match(g_get('wireless_regex'), $cfg['if'])) {
6037
					$wanif = interface_get_wireless_clone($cfg['if']);
6038
				} else {
6039
					$wanif = $cfg['if'];
6040
				}
6041
			}
6042
			break;
6043
	}
6044

    
6045
	return $wanif;
6046
}
6047

    
6048
/* Guess the physical interface by providing a IP address */
6049
function guess_interface_from_ip($ipaddress) {
6050

    
6051
	if (!is_ipaddr($ipaddress)) {
6052
		return false;
6053
	}
6054

    
6055
	$route = route_get($ipaddress, '', true);
6056
	if (empty($route)) {
6057
		return false;
6058
	}
6059

    
6060
	if (!empty($route[0]['interface-name'])) {
6061
		return $route[0]['interface-name'];
6062
	}
6063

    
6064
	return false;
6065
}
6066

    
6067
/*
6068
 * find_ip_interface($ip): return the interface where an ip is defined
6069
 *   (or if $bits is specified, where an IP within the subnet is defined)
6070
 */
6071
function find_ip_interface($ip, $bits = null) {
6072
	if (!is_ipaddr($ip)) {
6073
		return false;
6074
	}
6075

    
6076
	$isv6ip = is_ipaddrv6($ip);
6077

    
6078
	/* if list */
6079
	$ifdescrs = get_configured_interface_list();
6080

    
6081
	foreach ($ifdescrs as $ifname) {
6082
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
6083
		if (is_null($ifip)) {
6084
			continue;
6085
		}
6086
		if (is_null($bits)) {
6087
			if ($ip == $ifip) {
6088
				$int = get_real_interface($ifname);
6089
				return $int;
6090
			}
6091
		} else {
6092
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
6093
				$int = get_real_interface($ifname);
6094
				return $int;
6095
			}
6096
		}
6097
	}
6098

    
6099
	return false;
6100
}
6101

    
6102
/*
6103
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
6104
 *   (or if $bits is specified, where an IP within the subnet is found)
6105
 */
6106
function find_virtual_ip_alias($ip, $bits = null) {
6107

    
6108
	if (!is_ipaddr($ip)) {
6109
		return false;
6110
	}
6111

    
6112
	$isv6ip = is_ipaddrv6($ip);
6113

    
6114
	foreach (config_get_path('virtualip/vip', []) as $vip) {
6115
		if ($vip['mode'] === "ipalias") {
6116
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
6117
				continue;
6118
			}
6119
			if (is_null($bits)) {
6120
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
6121
					return $vip;
6122
				}
6123
			} else {
6124
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
6125
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
6126
					return $vip;
6127
				}
6128
			}
6129
		}
6130
	}
6131
	return false;
6132
}
6133

    
6134
function link_interface_to_track6($int, $action = "") {
6135
	$list = array();
6136
	if (empty($int)) {
6137
		return $list;
6138
	}
6139

    
6140
	foreach (config_get_path('interfaces', []) as $ifname => $ifcfg) {
6141
		if (!isset($ifcfg['enable'])) {
6142
			continue;
6143
		}
6144
		if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
6145
			if ($action == "update") {
6146
				interface_track6_configure($ifname, $ifcfg);
6147
			} elseif ($action == "") {
6148
				$list[$ifname] = $ifcfg;
6149
			}
6150
		}
6151
	}
6152
	return $list;
6153
}
6154

    
6155
function interface_find_child_cfgmtu($realiface) {
6156
	$vlans = link_interface_to_vlans($realiface);
6157
	$qinqs = link_interface_to_qinqs($realiface);
6158
	$bridge = link_interface_to_bridge($realiface);
6159
	$mtu = 0;
6160

    
6161
	foreach ([$vlans, $qinqs, ['bridge' => $bridge]] as $ints) {
6162
		if (is_array($ints)) {
6163
			foreach ($ints as $int) {
6164
				$ifass = convert_real_interface_to_friendly_interface_name($int['vlanif']);
6165
				if (!empty($ifass) &&
6166
				    config_path_enabled("interfaces/{$ifass}") &&
6167
				    (intval(config_get_path("interfaces/{$ifass}/mtu")) > $mtu)) {
6168
					$mtu = config_get_path("interfaces/{$ifass}/mtu");
6169
				}
6170
			}
6171
		}
6172
	}
6173

    
6174
	unset($vlans, $qinqs, $bridge);
6175
	return $mtu;
6176
}
6177

    
6178
function link_interface_to_vlans($int, $action = "") {
6179
	if (empty($int)) {
6180
		return;
6181
	}
6182

    
6183
	$ifaces = array();
6184
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
6185
		if ($int == $vlan['if']) {
6186
			if ($action == "update") {
6187
				interfaces_bring_up($int);
6188
			} else {
6189
				$ifaces[$vlan['tag']] = $vlan;
6190
			}
6191
		}
6192
	}
6193
	if (!empty($ifaces)) {
6194
		return $ifaces;
6195
	}
6196
}
6197

    
6198
function link_interface_to_qinqs($int, $action = "") {
6199
	if (empty($int)) {
6200
		return;
6201
	}
6202

    
6203
	$ifaces = array();
6204
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
6205
		if ($int == $qinq['if']) {
6206
			if ($action == "update") {
6207
				interfaces_bring_up($int);
6208
			} else {
6209
				$ifaces[$qinq['tag']] = $qinq;
6210
			}
6211
		}
6212
	}
6213
	if (!empty($ifaces)) {
6214
		return $ifaces;
6215
	}
6216
}
6217

    
6218
function link_interface_to_vips($int, $action = "", $vhid = '') {
6219
	$updatevips = false;
6220

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

    
6245
	return NULL;
6246
}
6247

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

    
6264
function link_interface_to_lagg($int) {
6265
	foreach (config_get_path('laggs/lagg', []) as $lagg) {
6266
		if (in_array($int, explode(',', $lagg['members']))) {
6267
			return "{$lagg['laggif']}";
6268
		}
6269
	}
6270
}
6271

    
6272
function link_interface_to_group($int) {
6273
	$result = array();
6274

    
6275
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $group) {
6276
		if (in_array($int, explode(" ", $group['members']))) {
6277
			$result[$group['ifname']] = $int;
6278
		}
6279
	}
6280

    
6281
	return $result;
6282
}
6283

    
6284
function link_interface_to_tunnelif($interface, $type, $remote = 'any') {
6285
	$result = array();
6286

    
6287
	if (empty($interface)) {
6288
		return $result;
6289
	}
6290

    
6291
	if (!in_array($type, array('gre', 'gif'))) {
6292
		return $result;
6293
	}
6294

    
6295
	foreach (config_get_path("{$type}s/{$type}", []) as $tunnel) {
6296
		if (($tunnel['if'] == $interface) &&
6297
			(($remote == 'any') ||
6298
			 (is_ipaddrv4($tunnel['remote-addr']) && ($remote == 'inet')) ||
6299
			 (is_ipaddrv6($tunnel['remote-addr']) && ($remote == 'inet6')))) {
6300
			$result[] = $tunnel;
6301
		}
6302
	}
6303

    
6304
	return $result;
6305
}
6306

    
6307
function link_interface_to_ppp_tunnelif($interface) {
6308
	$result = array();
6309

    
6310
	if (empty($interface)) {
6311
		return $result;
6312
	}
6313

    
6314
	config_init_path('ppps/ppp');
6315
	$realif = get_real_interface($interface);
6316
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
6317
		if (($ppp['ports'] == $realif) && in_array($ppp['type'], array('l2tp', 'pptp'))) {
6318
			$result[] = $ppp;
6319
		}
6320
	}
6321

    
6322
	return $result;
6323
}
6324

    
6325
/*
6326
 * find_interface_ip($interface): return the interface ip (first found)
6327
 */
6328
function find_interface_ip($interface, $flush = false) {
6329
	global $interface_ip_arr_cache;
6330
	global $interface_sn_arr_cache;
6331

    
6332
	$interface = str_replace("\n", "", $interface);
6333

    
6334
	if (!does_interface_exist($interface)) {
6335
		return;
6336
	}
6337

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

    
6359
	return $interface_ip_arr_cache[$interface];
6360
}
6361

    
6362
/*
6363
 * find_interface_ipv6($interface): return the interface ip (first found)
6364
 */
6365
function find_interface_ipv6($interface, $flush = false) {
6366
	global $interface_ipv6_arr_cache;
6367
	global $interface_snv6_arr_cache;
6368

    
6369
	$interface = trim($interface);
6370
	$interface = get_real_interface($interface);
6371

    
6372
	if (!does_interface_exist($interface)) {
6373
		return;
6374
	}
6375

    
6376
	/* Setup IP cache */
6377
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6378
		$ifinfo = get_interface_addresses($interface);
6379
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6380
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6381
	}
6382

    
6383
	return $interface_ipv6_arr_cache[$interface];
6384
}
6385

    
6386
/*
6387
 * Return the interface ipv6 link local address
6388
 */
6389
function find_interface_ipv6_ll($interface, $flush = false, $usefirst = true) {
6390
	global $interface_llv6_arr_cache;
6391

    
6392
	$interface = str_replace("\n", "", $interface);
6393

    
6394
	if (!does_interface_exist($interface)) {
6395
		return;
6396
	}
6397

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

    
6417
function find_interface_subnet($interface, $flush = false) {
6418
	global $interface_sn_arr_cache;
6419
	global $interface_ip_arr_cache;
6420

    
6421
	$interface = str_replace("\n", "", $interface);
6422
	if (does_interface_exist($interface) == false) {
6423
		return;
6424
	}
6425

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

    
6432
	return $interface_sn_arr_cache[$interface];
6433
}
6434

    
6435
function find_interface_subnetv6($interface, $flush = false) {
6436
	global $interface_snv6_arr_cache;
6437
	global $interface_ipv6_arr_cache;
6438

    
6439
	$interface = str_replace("\n", "", $interface);
6440
	if (does_interface_exist($interface) == false) {
6441
		return;
6442
	}
6443

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

    
6450
	return $interface_snv6_arr_cache[$interface];
6451
}
6452

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

    
6471
	return false;
6472
}
6473

    
6474
function get_possible_listen_ips($include_ipv6_link_local=false) {
6475

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

    
6497
	$interfaces['lo0'] = 'Localhost';
6498

    
6499
	return $interfaces;
6500
}
6501

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

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

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

    
6536
	$realif = get_failover_interface($interface, 'inet');
6537
	if (!$realif) {
6538
		return null;
6539
	}
6540

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

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

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

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

    
6573
	$realif = get_failover_interface($interface, 'inet6');
6574
	if (!$realif) {
6575
		return null;
6576
	}
6577

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

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

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

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

    
6635
function get_interface_linklocal($interface = "wan") {
6636

    
6637
	$realif = get_failover_interface($interface, 'inet6');
6638
	if (!$realif) {
6639
		return null;
6640
	}
6641

    
6642
	if (substr($interface, 0, 4) == '_vip') {
6643
		$realif = get_real_interface($interface);
6644
	} elseif (substr($interface, 0, 5) == '_lloc') {
6645
		$realif = get_real_interface(substr($interface, 5));
6646
	}
6647

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

    
6656
/**
6657
 * Get the first IPv6 address that is not a VIP or Link-Local address.
6658
 * Prioritize IPv6 GUA over ULA.
6659
 * 
6660
 * @param string $interface Interface to check
6661
 * @return array|bool IP address and prefix length; false If no match is found
6662
 */
6663
function get_interface_track6ip($interface = "wan") {
6664
	$ifinfo = get_interface_addresses(get_real_interface($interface));
6665

    
6666
	if (isset($ifinfo['ipaddr6']) && isset($ifinfo['subnetbits6'])) {
6667
		return [$ifinfo['ipaddr6'], $ifinfo['subnetbits6']];
6668
	}
6669

    
6670
	return false;
6671
}
6672

    
6673
function get_interface_subnet($interface = "wan") {
6674
	if (substr($interface, 0, 4) == '_vip') {
6675
		return (get_configured_vip_subnetv4($interface));
6676
	}
6677

    
6678
	$iface = config_get_path("interfaces/{$interface}");
6679
	if (is_array($iface) && !empty($iface['subnet']) && is_ipaddrv4($iface['ipaddr'])) {
6680
		return ($iface['subnet']);
6681
	}
6682

    
6683
	$realif = get_real_interface($interface);
6684
	if (!$realif) {
6685
		return (NULL);
6686
	}
6687

    
6688
	$cursn = find_interface_subnet($realif);
6689
	if (!empty($cursn)) {
6690
		return ($cursn);
6691
	}
6692

    
6693
	return (NULL);
6694
}
6695

    
6696
function get_interface_subnetv6($interface = "wan") {
6697
	if (substr($interface, 0, 4) == '_vip') {
6698
		return (get_configured_vip_subnetv6($interface));
6699
	} elseif (substr($interface, 0, 5) == '_lloc') {
6700
		$interface = substr($interface, 5);
6701
	}
6702

    
6703
	$iface = config_get_path("interfaces/{$interface}");
6704
	if (is_array($iface) && !empty($iface['subnetv6']) && is_ipaddrv6($iface['ipaddrv6'])) {
6705
		return ($iface['subnetv6']);
6706
	}
6707

    
6708
	$realif = get_real_interface($interface, 'inet6');
6709
	if (!$realif) {
6710
		return (NULL);
6711
	}
6712

    
6713
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6714
	if (config_get_path("interfaces/{$interface}/ipaddrv6") == 'track6') {
6715
		$curip = get_interface_track6ip($interface);
6716
		if ($curip) {
6717
			return $curip[1];
6718
		}
6719
	}
6720

    
6721
	$cursn = find_interface_subnetv6($realif);
6722
	if (!empty($cursn)) {
6723
		return ($cursn);
6724
	}
6725

    
6726
	return (NULL);
6727
}
6728

    
6729
/* return outside interfaces with a gateway */
6730
function get_interfaces_with_gateway() {
6731

    
6732
	$ints = array();
6733

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

    
6753
				break;
6754
		}
6755
	}
6756
	return $ints;
6757
}
6758

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

    
6794
	return false;
6795
}
6796

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

    
6826
	return false;
6827
}
6828

    
6829
/****f* interfaces/is_altq_capable
6830
 * NAME
6831
 *   is_altq_capable - Test if interface is capable of using ALTQ
6832
 * INPUTS
6833
 *   $int            - string containing interface name
6834
 * RESULT
6835
 *   boolean         - true or false
6836
 ******/
6837

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

    
6853
	$int_family = remove_ifindex($int);
6854

    
6855
	if (in_array($int_family, $capable)) {
6856
		return true;
6857
	} elseif (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6858
		return true;
6859
	} elseif (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6860
		return true;
6861
	} elseif (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6862
		return true;
6863
	} else {
6864
		return false;
6865
	}
6866
}
6867

    
6868
/****f* interfaces/is_interface_wireless
6869
 * NAME
6870
 *   is_interface_wireless - Returns if an interface is wireless
6871
 * RESULT
6872
 *   $tmp       - Returns if an interface is wireless
6873
 ******/
6874
function is_interface_wireless($interface) {
6875
	global $g;
6876

    
6877
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6878
	if (config_get_path("interfaces/{$friendly}/wireless") === null) {
6879
		if (preg_match(g_get('wireless_regex'), $interface)) {
6880
			config_init_path("interfaces/{$friendly}/wireless");
6881
			return true;
6882
		}
6883
		return false;
6884
	} else {
6885
		return true;
6886
	}
6887
}
6888

    
6889
function get_wireless_modes($interface) {
6890
	/* return wireless modes and channels */
6891
	$wireless_modes = array();
6892

    
6893
	$cloned_interface = get_real_interface($interface);
6894

    
6895
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6896
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
6897
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\n\" \$3 }'";
6898
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
6899

    
6900
		$interface_channels = [];
6901
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6902
		$interface_channel_count = count($interface_channels);
6903

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

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

    
6942
		$interface_channels = [];
6943
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
6944
		return $interface_channels;
6945
}
6946

    
6947
/* return wireless HT modes */
6948
function get_wireless_ht_modes($interface) {
6949
	$wireless_hts_supported = array(0 => gettext('Auto'));
6950

    
6951
	$cloned_interface = get_real_interface($interface);
6952

    
6953
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6954
		$interface_channels = get_wireless_channels($cloned_interface);
6955

    
6956
		foreach ($interface_channels as $channel) {
6957
			$channel_line = explode(",", $channel);
6958
			$wireless_ht = trim($channel_line[1]);
6959
			if (!empty($wireless_ht)) {
6960
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
6961
			}
6962
		}
6963
	}
6964
	return($wireless_hts_supported);
6965
}
6966

    
6967
/* return wireless HT by channel/standard */
6968
function get_wireless_ht_list($interface) {
6969
	$wireless_hts = array();
6970

    
6971
	$cloned_interface = get_real_interface($interface);
6972

    
6973
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
6974
		$interface_channels = get_wireless_channels($cloned_interface);
6975
		$interface_channel_count = count($interface_channels);
6976

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

    
7003
/* return channel numbers, frequency, max txpower, and max regulation txpower */
7004
function get_wireless_channel_info($interface) {
7005
	$wireless_channels = array();
7006

    
7007
	$cloned_interface = get_real_interface($interface);
7008

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

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

    
7017
		foreach ($interface_channels as $channel_line) {
7018
			$channel_line = explode(",", $channel_line);
7019
			if (!isset($wireless_channels[$channel_line[0]])) {
7020
				$wireless_channels[$channel_line[0]] = $channel_line;
7021
			}
7022
		}
7023
	}
7024
	return($wireless_channels);
7025
}
7026

    
7027
function set_interface_mtu($interface, $mtu) {
7028

    
7029
	/* LAGG interface must be destroyed and re-created to change MTU */
7030
	if ((substr($interface, 0, 4) == 'lagg') &&
7031
	    (!strstr($interface, "."))) {
7032
		foreach (config_get_path('laggs/lagg', []) as $lagg) {
7033
			if ($lagg['laggif'] == $interface) {
7034
				interface_lagg_configure($lagg);
7035
				break;
7036
			}
7037
		}
7038
	} else {
7039
		pfSense_interface_mtu($interface, $mtu);
7040
		set_ipv6routes_mtu($interface, $mtu);
7041
	}
7042
}
7043

    
7044
/****f* interfaces/get_interface_mtu
7045
 * NAME
7046
 *   get_interface_mtu - Return the mtu of an interface
7047
 * RESULT
7048
 *   $tmp       - Returns the mtu of an interface
7049
 ******/
7050
function get_interface_mtu($interface) {
7051
	$mtu = pfSense_interface_getmtu($interface);
7052
	return $mtu['mtu'];
7053
}
7054

    
7055
function get_interface_mac($interface) {
7056
	$macinfo = get_interface_addresses($interface);
7057
	return $macinfo["macaddr"];
7058
}
7059

    
7060
function get_interface_vendor_mac($interface) {
7061
	global $g;
7062

    
7063
	$macinfo = get_interface_addresses($interface);
7064
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7065
	    "00:00:00:00:00:00") {
7066
		return ($macinfo["hwaddr"]);
7067
	}
7068

    
7069
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7070
	if (file_exists($hwaddr_file)) {
7071
		$macaddr = trim(file_get_contents($hwaddr_file));
7072
		if (is_macaddr($macaddr)) {
7073
			return ($macaddr);
7074
		}
7075
	} elseif (is_macaddr($macinfo['macaddr'])) {
7076
		/* Save original macaddress to be restored when necessary */
7077
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7078
	}
7079

    
7080
	return (NULL);
7081
}
7082

    
7083
/****f* pfsense-utils/generate_random_mac_address
7084
 * NAME
7085
 *   generate_random_mac - generates a random mac address
7086
 * INPUTS
7087
 *   none
7088
 * RESULT
7089
 *   $mac - a random mac address
7090
 ******/
7091
function generate_random_mac_address() {
7092
	$mac = "02";
7093
	for ($x = 0; $x < 5; $x++) {
7094
		$mac .= ":" . dechex(rand(16, 255));
7095
	}
7096
	return $mac;
7097
}
7098

    
7099
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7100
	global $g;
7101

    
7102
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7103

    
7104
	if (!empty($iface) && !empty($pppif)) {
7105
		$cron_cmd = <<<EOD
7106
#!/bin/sh
7107
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7108
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7109

    
7110
EOD;
7111

    
7112
		@file_put_contents($cron_file, $cron_cmd);
7113
		chmod($cron_file, 0755);
7114
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7115
	} else {
7116
		unlink_if_exists($cron_file);
7117
	}
7118
}
7119

    
7120
function get_interface_default_mtu($type = "ethernet") {
7121
	switch ($type) {
7122
		case "gre":
7123
			return 1476;
7124
			break;
7125
		case "gif":
7126
			return 1280;
7127
			break;
7128
		case "tun":
7129
		case "vlan":
7130
		case "tap":
7131
		case "ethernet":
7132
		default:
7133
			return 1500;
7134
			break;
7135
	}
7136

    
7137
	/* Never reached */
7138
	return 1500;
7139
}
7140

    
7141
function get_vip_descr($ipaddress) {
7142

    
7143
	foreach (config_get_path('virtualip/vip', []) as $vip) {
7144
		if ($vip['subnet'] == $ipaddress) {
7145
			return ($vip['descr']);
7146
		}
7147
	}
7148
	return "";
7149
}
7150

    
7151
function interfaces_staticarp_configure($if) {
7152
	if (config_get_path('system/developerspew')) {
7153
		$mt = microtime();
7154
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7155
	}
7156

    
7157
	if (empty(config_get_path("interfaces/{$if}"))) {
7158
		return 0;
7159
	}
7160

    
7161
	$ifcfg = config_get_path("interfaces/{$if}");
7162

    
7163
	/* Enable staticarp, if enabled */
7164
	$staticarp = config_get_path("dhcpd/{$if}/staticarp");
7165
	if ($staticarp) {
7166
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7167
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7168
	} else {
7169
		/*
7170
		 * Interfaces do not have staticarp enabled by default
7171
		 * Let's not disable staticarp on freshly created interfaces
7172
		 */
7173
		if (!is_platform_booting()) {
7174
			mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7175
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7176
		}
7177
	}
7178

    
7179
	/* Enable static arp entries */
7180
	$staticmap = config_get_path("dhcpd/{$if}/staticmap", []);
7181
	if (is_array($staticmap)) {
7182
		foreach ($staticmap as $arpent) {
7183
			if (empty($arpent['ipaddr']) || empty($arpent['mac'])) {
7184
				continue;
7185
			}
7186
			if ($staticarp || isset($arpent['arp_table_static_entry'])) {
7187
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7188
			}
7189
		}
7190
	}
7191

    
7192
	return 0;
7193
}
7194

    
7195
function get_failover_interface($interface, $family = "all") {
7196
	/* shortcut to get_real_interface if we find it in the config */
7197
	if (is_array(config_get_path("interfaces/{$interface}"))) {
7198
		return get_real_interface($interface, $family);
7199
	}
7200

    
7201
	/* compare against gateway groups */
7202
	$a_groups = return_gateway_groups_array(true);
7203
	if (is_array($a_groups[$interface])) {
7204
		/* we found a gateway group, fetch the interface or vip */
7205
		if (!empty($a_groups[$interface][0]['vip'])) {
7206
			return $a_groups[$interface][0]['vip'];
7207
		} else {
7208
			return $a_groups[$interface][0]['int'];
7209
		}
7210
	}
7211
	/* fall through to get_real_interface */
7212
	/* XXX: Really needed? */
7213
	return get_real_interface($interface, $family);
7214
}
7215

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

    
7238
	if ($family == 6) {
7239
		$dhcp_string = "_DHCP6";
7240
	} else {
7241
		$dhcp_string = "_DHCP";
7242
	}
7243

    
7244
	foreach (config_get_path('gateways/gateway_group', []) as $group) {
7245
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7246
			continue;
7247
		}
7248
		foreach ($group['item'] as $item) {
7249
			$item_data = explode("|", $item);
7250
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7251
				return true;
7252
			}
7253
		}
7254
	}
7255

    
7256
	return false;
7257
}
7258

    
7259
function remove_ifindex($ifname) {
7260
	return preg_replace("/[0-9]+$/", "", $ifname);
7261
}
7262

    
7263
function get_configured_vip_list_with_descr($family = 'all', $type = VIP_ALL) {
7264
	$interfaces = array();	// In case there are no VIPs defined
7265

    
7266
	$viplist = get_configured_vip_list($family, $type);
7267
	foreach ($viplist as $vipid => $address) {
7268
		$interfaces[$vipid] = $address;
7269
		if ($type = VIP_CARP) {
7270
			$vip = get_configured_vip($vipid);
7271
			if (isset($vip) && is_array($vip) ) {
7272
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7273
			}
7274
		}
7275
		if (get_vip_descr($address)) {
7276
			$interfaces[$vipid] .= " (" . get_vip_descr($address) . ")";
7277
		}
7278
	}
7279
	return $interfaces;
7280
}
7281

    
7282
function return_gateway_groups_array_with_descr() {
7283
	$interfaces = array();
7284
	$grouplist = return_gateway_groups_array();
7285
	foreach (array_keys($grouplist) as $name) {
7286
		$interfaces[$name] = "GW Group {$name}";
7287
	}
7288
	return $interfaces;
7289
}
7290

    
7291
function get_serial_ports($short=false) {
7292
	$linklist = array();
7293
	if (!is_dir("/var/spool/lock")) {
7294
		mwexec("/bin/mkdir -p /var/spool/lock");
7295
	}
7296
	$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);
7297
	foreach ($serialports as $port) {
7298
		$port = trim($port);
7299
		$port = ($short) ? basename($port) : $port;
7300
		$linklist[$port] = $port;
7301
	}
7302
	return $linklist;
7303
}
7304

    
7305
function get_interface_ports() {
7306
	$linklist = array();
7307
	$portlist = get_interface_list();
7308

    
7309
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
7310
		if (empty($vlan)) {
7311
			continue;
7312
		}
7313
		$portlist[$vlan['vlanif']] = $vlan;
7314
	}
7315

    
7316
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
7317
		if (empty($qinq)) {
7318
			continue;
7319
		}
7320
		$members = explode(" ", $qinq['members']);
7321
		foreach ($members as $mem) {
7322
			$qentry = $qinq['vlanif'] . "." . $mem;
7323
			$portlist[$qentry] = $qentry;
7324
		}
7325
	}
7326

    
7327
	foreach ($portlist as $ifn => $ifinfo) {
7328
		$string = "";
7329
		if (is_array($ifinfo)) {
7330
			$string .= $ifn;
7331
			if ($ifinfo['mac']) {
7332
				$string .= " ({$ifinfo['mac']})";
7333
			}
7334
			if ($ifinfo['friendly']) {
7335
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7336
			} elseif ($ifinfo['descr']) {
7337
				$string .= " - {$ifinfo['descr']}";
7338
			}
7339
		} else {
7340
			$string .= $ifinfo;
7341
		}
7342

    
7343
		$linklist[$ifn] = $string;
7344
	}
7345
	return $linklist;
7346
}
7347

    
7348
function build_ppps_link_list() {
7349
	global $pconfig;
7350

    
7351
	$linklist = array('list' => array(), 'selected' => array());
7352

    
7353
	if ($pconfig['type'] == 'ppp') {
7354
		$linklist['list'] = get_serial_ports();
7355
	} else {
7356
		$iflist = get_interface_ports();
7357

    
7358
		$viplist = array();
7359
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7360
		foreach ($carplist as $vid => $vaddr) {
7361
			$vip = get_configured_vip($vid);
7362
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7363
		}
7364

    
7365
		$linklist['list'] = array_merge($iflist, $viplist);
7366

    
7367
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7368
		$lagglist = get_lagg_interface_list();
7369
		foreach ($lagglist as $lagg) {
7370
			/* LAGG members cannot be assigned */
7371
			$laggmembers = explode(',', $lagg['members']);
7372
			foreach ($laggmembers as $lagm) {
7373
				if (isset($linklist['list'][$lagm])) {
7374
					unset($linklist['list'][$lagm]);
7375
				}
7376
			}
7377
		}
7378
	}
7379

    
7380
	$selected_ports = array();
7381
	if (is_array($pconfig['interfaces'])) {
7382
		$selected_ports = $pconfig['interfaces'];
7383
	} elseif (!empty($pconfig['interfaces'])) {
7384
		$selected_ports = explode(',', $pconfig['interfaces']);
7385
	}
7386
	foreach ($selected_ports as $port) {
7387
		if (isset($linklist['list'][$port])) {
7388
			array_push($linklist['selected'], $port);
7389
		}
7390
	}
7391
	return($linklist);
7392
}
7393

    
7394
function create_interface_list($open = false) {
7395
	$iflist = array();
7396

    
7397
	// add group interfaces
7398
	config_get_path('ifgroups/ifgroupentry', []);
7399
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $ifgen) {
7400
		if ($open || have_ruleint_access($ifgen['ifname'])) {
7401
			$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7402
		}
7403
	}
7404

    
7405
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7406
		if ($open || have_ruleint_access($ifent)) {
7407
			$iflist[$ifent] = $ifdesc;
7408
		}
7409
	}
7410

    
7411
	if (config_get_path('l2tp/mode', "") == "server" && ($open || have_ruleint_access("l2tp"))) {
7412
		$iflist['l2tp'] = gettext('L2TP VPN');
7413
	}
7414

    
7415
	if (is_pppoe_server_enabled() && ($open || have_ruleint_access("pppoe"))) {
7416
		$iflist['pppoe'] = gettext("PPPoE Server");
7417
	}
7418

    
7419
	// add ipsec interfaces
7420
	if (ipsec_enabled() && ($open || have_ruleint_access("enc0"))) {
7421
		$iflist["enc0"] = gettext("IPsec");
7422
	}
7423

    
7424
	// add openvpn/tun interfaces
7425
	if (config_get_path('openvpn/openvpn-server') || config_get_path('openvpn/openvpn-client')) {
7426
		$iflist["openvpn"] = gettext("OpenVPN");
7427
	}
7428

    
7429
	return($iflist);
7430
}
7431

    
7432
function is_pseudo_interface($inf, $tap=true) {
7433
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7434
	foreach ($psifs as $pif) {
7435
		if (substr($inf, 0, strlen($pif)) == $pif) {
7436
			if (($pif == 'ovpn') && $tap) {
7437
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7438
				$type = ($m[1] == 'c') ? 'client' : 'server';
7439
				foreach (config_get_path("openvpn/openvpn-{$type}", []) as $ovpn) {
7440
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7441
						return false;
7442
					} elseif ($ovpn['vpnid'] == $m[2]) {
7443
						return true;
7444
					}
7445
				}
7446
			} else {
7447
				return true;
7448
			}
7449
		}
7450
	}
7451
	return false;
7452
}
7453

    
7454
function is_stf_interface($inf) {
7455
	switch (config_get_path("interfaces/{$inf}/ipaddrv6")) {
7456
		case '6rd':
7457
		case '6to4':
7458
			return true;
7459
		default:
7460
			return false;
7461
	}
7462
}
7463

    
7464
function restart_interface_services($interface, $ipv6type = "") {
7465

    
7466
	services_unbound_configure(true, $interface);
7467

    
7468
	services_igmpproxy_configure($interface);
7469
	services_snmpd_configure($interface);
7470
	vpn_l2tp_configure($interface);
7471

    
7472
	if (substr(config_get_path("interfaces/{$interface}/if",""), 0, 4) != "ovpn") {
7473
		openvpn_resync_all($interface);
7474
	}
7475
	ipsec_force_reload($interface);
7476

    
7477
	/* restart RADVD to announce correct IPv6 prefix
7478
	 * see https://redmine.pfsense.org/issues/12604 */
7479
	if ((is_ipaddrv6($ipv6type) || ($ipv6type == "track6")) &&
7480
	    (config_get_path("dhcpdv6/{$interface}/ramode", "disabled") != "disabled")) {
7481
		services_radvd_configure();
7482
	}
7483

    
7484
	if (config_path_enabled("dhcpd/{$interface}") ||
7485
	    config_path_enabled("dhcpdv6/{$interface}")) {
7486
		services_dhcpd_configure();
7487
	}
7488

    
7489
	config_init_path('syslog');
7490
	if (config_path_enabled('syslog') && ($interface == config_get_path('syslog/sourceip'))) {
7491
		system_syslogd_start();
7492
	}
7493
}
7494

    
7495
/**
7496
 * Return interface parameters and primary ipv4 and ipv6 addresses for the real iface
7497
 * $interface, identified by exclusion of VIPs. Deprecates pfSense_get_interface_addresses()
7498
 *
7499
 * Result array contains keyed values:
7500
 * - ipaddr: ipv4 address
7501
 * - subnetbits: ipv4 subnet bits
7502
 * - subnet: ipv4 subnet
7503
 * - broadcast: ipv4 broadcast addr (if applicable)
7504
 * - tunnel: ipv4 PPP endpoint (if applicable)
7505
 * - ipaddr6: ipv6 address
7506
 * - tentative: ipv6 tentative flag (if applicable)
7507
 * - subnetbits6: ipv6 subnet bits
7508
 * - tunnel6: ipv6 tunnel endpoint
7509
 * - status: up or down interface status
7510
 * - link0: per link layer defined flag
7511
 * - link1: per link layer defined flag
7512
 * - link2: per link layer defined flag
7513
 * - multicast: multicast support
7514
 * - loopback: interface is a loopback interface
7515
 * - pointtopoint: interface is point-to-point
7516
 * - promisc: interface in promisc mode
7517
 * - permanentpromisc: interface permanently in promisc mode
7518
 * - oactive: interface tx hardware queue is full
7519
 * - allmulti: interface receives all multicast packets
7520
 * - simplex: interface is simplex
7521
 * - linkstateup: interface link is up
7522
 * - iftype: wireless, ether, vlan, bridge, virtual, other
7523
 * - mtu: mtu of interface
7524
 * - caps: interface capabilities array
7525
 * - encaps: enabled capabilities array
7526
 * - macaddr: interface configured ethernet address
7527
 * - hwaddr: hardware ethernet address
7528
 */
7529
function get_interface_addresses($interface) {
7530
	$v4addrs = array();
7531
	$v6addrs = array();
7532
	$v4vips = array();
7533
	$v6vips = array();
7534
	$ifaddrs = pfSense_get_ifaddrs($interface);
7535

    
7536
	foreach (array_keys(get_configured_vip_list()) as $viface) {
7537
		$vip = get_configured_vip($viface);
7538
		if (is_ipaddrv4($vip['subnet'])) {
7539
			array_push($v4vips, $vip['subnet']);
7540
		} else if (is_ipaddrv6($vip['subnet'])) {
7541
			array_push($v6vips, Net_IPv6::Uncompress($vip['subnet']));
7542
		}
7543
	}
7544

    
7545
	if ($ifaddrs['addrs']) {
7546
		$v4addrs = array_filter($ifaddrs['addrs'], function($addr) use ($v4vips){
7547
			return (array_search($addr['addr'], $v4vips) === false);
7548
		});
7549
	}
7550

    
7551
	if ($ifaddrs['addrs6']) {
7552
		$v6addrs = array_filter($ifaddrs['addrs6'], function($addr) use ($v6vips){
7553
			return (array_search(Net_IPv6::Uncompress($addr['addr']), $v6vips) === false);
7554
		});
7555
	}
7556
	/* Transform output to conform to pfSense_get_interface_addresses() */
7557
	if ($v4addrs) {
7558
		$v4addr = array_shift($v4addrs);
7559
		$ifaddrs['ipaddr'] = $v4addr['addr'];
7560
		foreach(array("subnetbits", "subnet", "broadcast", "tunnel") as $key) {
7561
			if (array_key_exists($key, $v4addr)) {
7562
				$ifaddrs[$key] = $v4addr[$key];
7563
			}
7564
		}
7565
	}
7566

    
7567
	if ($v6addrs) {
7568
		// use the first IPv6 GUA address if one exists, otherwise the first address
7569
		$v6addr = $v6addrs[array_key_first($v6addrs)];
7570
		foreach ($v6addrs as $addr) {
7571
			if (is_v6gua($addr['addr'])) {
7572
				$v6addr = $addr;
7573
				break;
7574
			}
7575
		}
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

    
7592
/**
7593
 * Returns all interface addresses, including IPv6 LL addresses.
7594
 * XXX: Review/refactor functions used to retrieve interfaces addresses.
7595
 */
7596
function get_interface_addresses_all(string $interface): array {
7597
	$addresses = [];
7598

    
7599
	// Get primary IPv4/6 addresses
7600
	$addresses_primary = get_interface_addresses($interface);
7601
	if (!empty($addresses_primary['ipaddr'])) {
7602
		$addresses[] = $addresses_primary['ipaddr'];
7603
	}
7604
	if (!empty($addresses_primary['ipaddr6'])) {
7605
		$addresses[] = $addresses_primary['ipaddr6'];
7606
	}
7607

    
7608
	// Get IPv6 link-local address
7609
	$addresses_linklocal = find_interface_ipv6_ll($interface);
7610
	if (!empty($addresses_linklocal)) {
7611
		$addresses_linklocal_pos = strpos($addresses_linklocal, '%');
7612
		if ($addresses_linklocal_pos !== false) {
7613
			$addresses_linklocal = substr($addresses_linklocal, 0, $addresses_linklocal_pos);
7614
		}
7615
		$addresses[] = $addresses_linklocal;
7616
	}
7617

    
7618
	// Get VIPs
7619
	foreach (array_keys(get_configured_vip_list()) as $viface) {
7620
		$vip = get_configured_vip($viface);
7621
		if ($vip['interface'] == $interface && !empty($vip['subnet'])) {
7622
			$addresses[] = $vip['subnet'];
7623
		}
7624
	}
7625

    
7626
	return $addresses;
7627
}
7628
?>
(22-22/61)