Project

General

Profile

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

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

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

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

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

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

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

    
62
	return true;
63
}
64

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

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

    
76
	return $interface_arr_cache;
77
}
78

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

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

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

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

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

    
109

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

    
125
	$ifacedata = pfSense_getall_interface_addresses($realif);
126

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

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

    
139
	return false;
140
}
141

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

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

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

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

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

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

    
213
function vlan_valid_tag($tag = NULL) {
214

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

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

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

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

    
237
        return (false);
238
}
239

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

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

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

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

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

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

    
278
	return (NULL);
279
}
280

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

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

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

    
295
	return (false);
296
}
297

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

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

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

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

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

    
329
	return (NULL);
330
}
331

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

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

    
345
	$current_mac = get_interface_mac($interface);
346

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

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

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

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

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

    
416
	return (FALSE);
417
}
418

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

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

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

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

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

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

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

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

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

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

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

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

    
496
	interfaces_bring_up($vlanif);
497

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

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

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

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

    
518
	return $vlanif;
519
}
520

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
648
	return $vlanif;
649
}
650

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

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

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

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

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

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

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

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

    
706
	return $vlanif;
707
}
708

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

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

    
716
	$iflist = get_configured_interface_list();
717

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

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

    
745
}
746

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
854
	$checklist = get_configured_interface_list();
855

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

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

    
877
	interface_bridge_configure_advanced($bridge);
878

    
879
	interface_bridge_configure_ip6linklocal($bridge);
880

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1161
	interfaces_bring_up($laggif);
1162

    
1163
	return $laggif;
1164
}
1165

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

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

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

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

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

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

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

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

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

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

    
1240
	interfaces_bring_up($greif);
1241

    
1242
	return $greif;
1243
}
1244

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

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

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

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

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

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

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

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

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

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

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

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

    
1406

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

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

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

    
1421
	interfaces_bring_up($gifif);
1422

    
1423
	return $gifif;
1424
}
1425

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

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

    
1441
	return false;
1442
}
1443

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1643
	$iface_addrs = array();
1644

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

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

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

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

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

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

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

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

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

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

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

    
1770
	interfaces_qinq_configure();
1771

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

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

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

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

    
1829
	/* set up IPsec VTI interfaces */
1830
	interfaces_ipsec_vti_configure();
1831

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

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

    
1841
	/* set up GIF virtual interfaces */
1842
	interfaces_tunnel_configure(1,'','gif');
1843

    
1844
	/* set up BRIDGE virtual interfaces */
1845
	interfaces_bridge_configure(1);
1846

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

    
1855
		interface_configure($if, $reload);
1856

    
1857
		if (platform_booting()) {
1858
			echo gettext("done.") . "\n";
1859
		}
1860
	}
1861

    
1862
	/* bring up vip interfaces */
1863
	interfaces_vips_configure();
1864

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

    
1868
	/* set up GIF virtual interfaces */
1869
	interfaces_tunnel_configure(2,'','gif');
1870

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

    
1879
		interface_configure($if, $reload);
1880

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

    
1886
	/* set up BRIDGE virtual interfaces */
1887
	interfaces_bridge_configure(2);
1888

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

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

    
1902
		if (platform_booting()) {
1903
			echo gettext("done.") . "\n";
1904
		}
1905
	}
1906

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

    
1915
		interface_configure($if, $reload);
1916

    
1917
		if (platform_booting()) {
1918
			echo gettext("done.") . "\n";
1919
		}
1920
	}
1921

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

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

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

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

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

    
1944
	return 0;
1945
}
1946

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
2183
	return;
2184
}
2185

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

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

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

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

    
2222
	return false;
2223
}
2224

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

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

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

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

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

    
2256
	return false;
2257
}
2258

    
2259
function interfaces_ptpid_next() {
2260

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

    
2266
	return $ptpid;
2267
}
2268

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

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

    
2281
	return NULL;
2282
}
2283

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

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

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

    
2294
	$itemhash = getMPDCRONSettings($pppif);
2295

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

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

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

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

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

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

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

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

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

    
2477
				if (!is_ipaddr($localips[$pid])) {
2478
					log_error(sprintf(gettext("Could not get a Local IP address for PPTP/L2TP link on %s in interfaces_ppps_configure. Using 0.0.0.0 ip!"), $port));
2479
					$localips[$pid] = "0.0.0.0";
2480
				}
2481
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2482
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2483
				}
2484
				if (!is_ipaddr($gateways[$pid])) {
2485
					log_error(sprintf(gettext('Could not get a PPTP/L2TP Remote IP address from %1$s for %2$s in interfaces_ppps_configure.'), $dhcp_gateway, $gway));
2486
					return 0;
2487
				}
2488
				pfSense_ngctl_attach(".", $port);
2489
				break;
2490
			case "ppp":
2491
				if (!file_exists("{$port}")) {
2492
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2493
					return 0;
2494
				}
2495
				break;
2496
			default:
2497
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2498
				break;
2499
		}
2500
	}
2501

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

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

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

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

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

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

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

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

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

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

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

    
2598
EOD;
2599
	}
2600

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

    
2605
EOD;
2606

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

    
2611
EOD;
2612
	}
2613

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

    
2634
EOD;
2635
	}
2636

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

    
2645
EOD;
2646

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

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

    
2657
EOD;
2658
	}
2659

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

    
2665
EOD;
2666
	}
2667

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

    
2672
EOD;
2673
	}
2674

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

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

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

    
2690
EOD;
2691
		}
2692

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

    
2697
EOD;
2698
		}
2699

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

    
2704
EOD;
2705
		}
2706

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

    
2712
EOD;
2713

    
2714

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

    
2719
EOD;
2720
		}
2721

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

    
2737
EOD;
2738
		}
2739

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

    
2746
EOD;
2747
		}
2748

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

    
2753
EOD;
2754
		}
2755

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

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

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

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

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

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

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

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

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

    
2828
EOD;
2829
		}
2830

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

    
2836
EOD;
2837
		}
2838

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

    
2844
EOD;
2845
		}
2846

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

    
2850

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

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

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

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

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

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

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

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

    
2957
	return 1;
2958
}
2959

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3295
	return $realif;
3296
}
3297

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3705
EOD;
3706

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

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

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

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

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

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

    
3741
EOD;
3742
						}
3743
					}
3744
				}
3745

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

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

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

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

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

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

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

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

    
3802
	fclose($fd_set);
3803

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

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

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

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

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

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

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

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

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

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

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

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

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

    
3908
	unset($wlcmd_args, $wlcmd);
3909

    
3910

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

    
3915
	return 0;
3916

    
3917
}
3918

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

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

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

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

    
3938
	return intval($pid);
3939
}
3940

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

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

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

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

    
3966
	return intval($pid);
3967
}
3968

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

    
3972
	$i = 0;
3973

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

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

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

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

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

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

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

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

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

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

    
4027
	$pid = find_dhcp6c_process($interface);
4028

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

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

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

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

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

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

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

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

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

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

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

    
4139
	return $mtu;
4140
}
4141

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

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

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

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

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

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

    
4182
	return $mtu;
4183
}
4184

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4379
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4380

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

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

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

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

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

    
4474
	interface_netgraph_needed($interface);
4475

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

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

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

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

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

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

    
4513
		if ($reloadall == true) {
4514

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4624
	return 0;
4625
}
4626

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

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

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

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

    
4647
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4648
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4649
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not valid, not configuring 6RD tunnel'), $ip4address, $lancfg['track6-interface']));
4650
		return;
4651
	}
4652
	$hexwanv4 = return_hex_ipv4($ip4address);
4653

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

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

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

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

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

    
4678
	$lanif = get_real_interface($interface);
4679
	$oip = find_interface_ipv6($lanif);
4680
	if (is_ipaddrv6($oip)) {
4681
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4682
	}
4683
	unset($interface_ipv6_arr_cache[$lanif]);
4684
	unset($interface_snv6_arr_cache[$lanif]);
4685
	log_error(sprintf(gettext('rd6 %1$s with ipv6 address %2$s based on %3$s ipv4 %4$s'), $interface, $rd6lan, $lancfg['track6-interface'], $ip4address));
4686
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4687

    
4688
	return 0;
4689
}
4690

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

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

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

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

    
4711
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4712
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4713
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $lancfg['track6-interface']));
4714
		return;
4715
	}
4716
	$hexwanv4 = return_hex_ipv4($ip4address);
4717

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

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

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

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

    
4738
	$lanif = get_real_interface($interface);
4739
	$oip = find_interface_ipv6($lanif);
4740
	if (is_ipaddrv6($oip)) {
4741
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4742
	}
4743
	unset($interface_ipv6_arr_cache[$lanif]);
4744
	unset($interface_snv6_arr_cache[$lanif]);
4745
	log_error(sprintf(gettext('sixto4 %1$s with ipv6 address %2$s based on %3$s ipv4 %4$s'), $interface, $sixto4lan, $lancfg['track6-interface'], $ip4address));
4746
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4747

    
4748
	return 0;
4749
}
4750

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

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

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

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

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

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

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

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

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

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

    
4803

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

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

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

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

    
4841
	return 0;
4842
}
4843

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
4953
	return 0;
4954
}
4955

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
5233
	if (isvalidpid("{$g['varrun_path']}/rtsold_{$wanif}.pid")) {
5234
		killbypid("{$g['varrun_path']}/rtsold_{$wanif}.pid");
5235
		log_error("Killing running rtsold process");
5236
		sleep(2);
5237
	}
5238

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

    
5281
	return 0;
5282
}
5283

    
5284
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5285
	global $g;
5286

    
5287
	$send_options = "";
5288
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
5289
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
5290
		foreach ($options as $option) {
5291
			$send_options .= "\tsend " . trim($option) . ";\n";
5292
		}
5293
	}
5294

    
5295
	$request_options = "";
5296
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5297
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5298
		foreach ($options as $option) {
5299
			$request_options .= "\trequest " . trim($option) . ";\n";
5300
		}
5301
	}
5302

    
5303
	$information_only = "";
5304
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5305
		$information_only = "\tinformation-only;\n";
5306
	}
5307

    
5308
	$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5309
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5310
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5311
	}
5312

    
5313
	$interface_statement  = "interface";
5314
	$interface_statement .= " {$wanif}";
5315
	$interface_statement .= " {\n";
5316
	$interface_statement .= "$send_options";
5317
	$interface_statement .= "$request_options";
5318
	$interface_statement .= "$information_only";
5319
	$interface_statement .= "$script";
5320
	$interface_statement .= "};\n";
5321

    
5322
	$id_assoc_statement_address = "";
5323
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5324
		$id_assoc_statement_address .= "id-assoc";
5325
		$id_assoc_statement_address .= " na";
5326
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5327
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5328
		}
5329
		$id_assoc_statement_address .= " { ";
5330

    
5331
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5332
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5333
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5334
			$id_assoc_statement_address .= "\n\taddress";
5335
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5336
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5337
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5338
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5339
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5340
			}
5341
			$id_assoc_statement_address .= ";\n";
5342
		}
5343

    
5344
		$id_assoc_statement_address .= "};\n";
5345
	}
5346

    
5347
	$id_assoc_statement_prefix = "";
5348
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5349
		$id_assoc_statement_prefix .= "id-assoc";
5350
		$id_assoc_statement_prefix .= " pd";
5351
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5352
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5353
		}
5354
		$id_assoc_statement_prefix .= " { ";
5355

    
5356
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5357
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5358
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5359
			$id_assoc_statement_prefix .= "\n\tprefix";
5360
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5361
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5362
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5363
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5364
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5365
			}
5366
			$id_assoc_statement_prefix .= ";";
5367
		}
5368

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

    
5382
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5383
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5384
			$id_assoc_statement_prefix .= "\n";
5385
		}
5386

    
5387
		$id_assoc_statement_prefix .= "};\n";
5388
	}
5389

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

    
5406
	$key_info_statement = "";
5407
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5408
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5409
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5410
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5411
		$key_info_statement .= "keyinfo";
5412
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5413
		$key_info_statement .= " {\n";
5414
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5415
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5416
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5417
		if (preg_match("/((([0-9]{4}-)?[0-9]{2}[0-9]{2} )?[0-9]{2}:[0-9]{2})||(foreever)/", $wancfg['adv_dhcp6_key_info_statement_expire'])) {
5418
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5419
		}
5420
		$key_info_statement .= "};\n";
5421
	}
5422

    
5423
	$dhcp6cconf  = $interface_statement;
5424
	$dhcp6cconf .= $id_assoc_statement_address;
5425
	$dhcp6cconf .= $id_assoc_statement_prefix;
5426
	$dhcp6cconf .= $authentication_statement;
5427
	$dhcp6cconf .= $key_info_statement;
5428

    
5429
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5430

    
5431
	return $dhcp6cconf;
5432
}
5433

    
5434

    
5435
function DHCP6_Config_File_Override($wancfg, $wanif) {
5436

    
5437
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5438

    
5439
	if ($dhcp6cconf === false) {
5440
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5441
		return '';
5442
	} else {
5443
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5444
	}
5445
}
5446

    
5447

    
5448
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5449

    
5450
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5451

    
5452
	return $dhcp6cconf;
5453
}
5454

    
5455

    
5456
function interface_dhcp_configure($interface = "wan") {
5457
	global $config, $g, $vlanprio_values;
5458

    
5459
	$ifcfg = $config['interfaces'][$interface];
5460
	if (empty($ifcfg)) {
5461
		$ifcfg = array();
5462
	}
5463

    
5464
	$dhclientconf_vlantag = "";
5465
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5466
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5467
	}
5468

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

    
5476
	if ($ifcfg['dhcphostname']) {
5477
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5478
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5479
	} else {
5480
		$dhclientconf_hostname = "";
5481
	}
5482

    
5483
	$realif = get_real_interface($interface);
5484
	if (empty($realif)) {
5485
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5486
		return 0;
5487
	}
5488
	$dhclientconf = "";
5489

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

    
5502
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5503
		$dhclientconf .= <<<EOD
5504

    
5505
	reject {$ifcfg['dhcprejectfrom']};
5506
EOD;
5507
	}
5508
	$dhclientconf .= <<<EOD
5509

    
5510
}
5511

    
5512
EOD;
5513

    
5514
	// DHCP Config File Advanced
5515
	if ($ifcfg['adv_dhcp_config_advanced']) {
5516
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5517
	}
5518

    
5519
	if (is_ipaddr($ifcfg['alias-address'])) {
5520
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5521
		$dhclientconf .= <<<EOD
5522
alias {
5523
	interface "{$realif}";
5524
	fixed-address {$ifcfg['alias-address']};
5525
	option subnet-mask {$subnetmask};
5526
}
5527

    
5528
EOD;
5529
	}
5530

    
5531
	// DHCP Config File Override
5532
	if ($ifcfg['adv_dhcp_config_file_override']) {
5533
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5534
	}
5535

    
5536
	fwrite($fd, $dhclientconf);
5537
	fclose($fd);
5538

    
5539
	/* bring wan interface up before starting dhclient */
5540
	if ($realif) {
5541
		interfaces_bring_up($realif);
5542
	}
5543

    
5544
	/* Make sure dhclient is not running */
5545
	kill_dhclient_process($realif);
5546

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

    
5550
	return 0;
5551
}
5552

    
5553
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5554

    
5555
	$hostname = "";
5556
	if ($ifcfg['dhcphostname'] != '') {
5557
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5558
	}
5559

    
5560
	/* DHCP Protocol Timings */
5561
	$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");
5562
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5563
		$pt_variable = "{$Protocol_Timing}";
5564
		${$pt_variable} = "";
5565
		if ($ifcfg[$Protocol_Timing] != "") {
5566
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5567
		}
5568
	}
5569

    
5570
	$send_options = "";
5571
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5572
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5573
		foreach ($options as $option) {
5574
			$send_options .= "\tsend " . trim($option) . ";\n";
5575
		}
5576
	}
5577

    
5578
	$request_options = "";
5579
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5580
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5581
	}
5582

    
5583
	$required_options = "";
5584
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5585
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5586
	}
5587

    
5588
	$option_modifiers = "";
5589
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5590
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5591
		foreach ($modifiers as $modifier) {
5592
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5593
		}
5594
	}
5595

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

    
5620
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5621

    
5622
	return $dhclientconf;
5623
}
5624

    
5625
function DHCP_Config_Option_Split($option_string) {
5626
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5627
	return $matches ? $matches[0] : [];
5628
}
5629

    
5630
function DHCP_Config_File_Override($ifcfg, $realif) {
5631

    
5632
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5633

    
5634
	if ($dhclientconf === false) {
5635
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5636
		return '';
5637
	} else {
5638
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5639
	}
5640
}
5641

    
5642

    
5643
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5644

    
5645
	/* Apply Interface Substitutions */
5646
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5647

    
5648
	/* Apply Hostname Substitutions */
5649
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5650

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

    
5657
	/* Apply MAC Address Substitutions */
5658
	foreach ($various_mac_types as $various_mac_type) {
5659
		foreach ($various_mac_cases as $various_mac_case) {
5660
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5661

    
5662
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5663
				if ($res !== false) {
5664

    
5665
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5666
					if ("$various_mac_case" == "U") {
5667
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5668
					}
5669
					if ("$various_mac_case" == "L") {
5670
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5671
					}
5672

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

    
5685
					/* MAC Address Delimiter Substitutions */
5686
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5687

    
5688
					/* Apply MAC Address Substitutions */
5689
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5690
				}
5691
			}
5692
		}
5693
	}
5694

    
5695
	return $dhclientconf;
5696
}
5697

    
5698
function interfaces_group_setup() {
5699
	global $config;
5700

    
5701
	if (!isset($config['ifgroups']['ifgroupentry']) ||
5702
	    !is_array($config['ifgroups']['ifgroupentry'])) {
5703
		return;
5704
	}
5705

    
5706
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5707
		interface_group_setup($groupar);
5708
	}
5709

    
5710
	return;
5711
}
5712

    
5713
function interface_group_setup(&$groupname /* The parameter is an array */) {
5714
	global $config;
5715

    
5716
	if (!is_array($groupname)) {
5717
		return;
5718
	}
5719
	$members = explode(" ", $groupname['members']);
5720
	foreach ($members as $ifs) {
5721
		$realif = get_real_interface($ifs);
5722
		if ($realif && does_interface_exist($realif)) {
5723
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5724
		}
5725
	}
5726

    
5727
	return;
5728
}
5729

    
5730
function is_interface_group($if) {
5731
	global $config;
5732

    
5733
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5734
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5735
			if ($groupentry['ifname'] === $if) {
5736
				return true;
5737
			}
5738
		}
5739
	}
5740

    
5741
	return false;
5742
}
5743

    
5744
function interface_group_add_member($interface, $groupname) {
5745
	$interface = get_real_interface($interface);
5746
	if (does_interface_exist($interface)) {
5747
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5748
	}
5749
}
5750

    
5751
/* COMPAT Function */
5752
function convert_friendly_interface_to_real_interface_name($interface) {
5753
	return get_real_interface($interface);
5754
}
5755

    
5756
/* COMPAT Function */
5757
function get_real_wan_interface($interface = "wan") {
5758
	return get_real_interface($interface);
5759
}
5760

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

    
5766
/*
5767
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5768
 */
5769
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5770
	global $config;
5771

    
5772
	/* XXX: For speed reasons reference directly the interface array */
5773
	init_config_arr(array('interfaces'));
5774
	$ifdescrs = &$config['interfaces'];
5775
	//$ifdescrs = get_configured_interface_list(true);
5776

    
5777
	foreach ($ifdescrs as $if => $ifname) {
5778
		if ($if == $interface || $ifname['if'] == $interface) {
5779
			return $if;
5780
		}
5781

    
5782
		if (get_real_interface($if) == $interface) {
5783
			return $if;
5784
		}
5785

    
5786
		if ($checkparent == false) {
5787
			continue;
5788
		}
5789

    
5790
		$int = get_parent_interface($if, true);
5791
		if (is_array($int)) {
5792
			foreach ($int as $iface) {
5793
				if ($iface == $interface) {
5794
					return $if;
5795
				}
5796
			}
5797
		}
5798
	}
5799

    
5800
	if ($interface == "enc0") {
5801
		return 'IPsec';
5802
	}
5803
}
5804

    
5805
/* attempt to resolve interface to friendly descr */
5806
function convert_friendly_interface_to_friendly_descr($interface) {
5807
	global $config;
5808

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

    
5867
				/* if list */
5868
				$ifdescrs = get_configured_interface_with_descr(true);
5869
				foreach ($ifdescrs as $if => $ifname) {
5870
					if ($if == $interface || $ifname == $interface) {
5871
						return $ifname;
5872
					}
5873
				}
5874
			}
5875
			break;
5876
	}
5877

    
5878
	return $ifdesc;
5879
}
5880

    
5881
function convert_real_interface_to_friendly_descr($interface) {
5882

    
5883
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5884

    
5885
	if (!empty($ifdesc)) {
5886
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5887
	}
5888

    
5889
	return $interface;
5890
}
5891

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

    
5904
	$parents = array();
5905
	//Check that we got a valid interface passed
5906
	$realif = get_real_interface($interface);
5907
	if ($realif == NULL) {
5908
		return $parents;
5909
	}
5910

    
5911
	// If we got a real interface, find it's friendly assigned name
5912
	if ($interface == $realif && $avoidrecurse == false) {
5913
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5914
	}
5915

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

    
5949
	if (empty($parents)) {
5950
		// Handle _vlans not assigned to an interface
5951
		$vlan = interface_is_vlan($realif);
5952
		if ($vlan != NULL) {
5953
			$parents[0] = $vlan['if'];
5954
		}
5955
	}
5956

    
5957
	if (empty($parents)) {
5958
		/* Handle LAGGs. */
5959
		$lagg = interface_is_type($realif, 'lagg');
5960
		if ($lagg != NULL && isset($lagg['members'])) {
5961
			$parents = explode(",", $lagg['members']);
5962
		}
5963
	}
5964

    
5965
	if (empty($parents)) {
5966
		$parents[0] = $realif;
5967
	}
5968

    
5969
	return $parents;
5970
}
5971

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

    
5980
	$realif = get_parent_interface($interface);
5981

    
5982
	if (substr($realif[0], 0, 4) == "lagg") {
5983
		foreach ($config['laggs']['lagg'] as $lagg) {
5984
			if ($realif[0] == $lagg['laggif']) {
5985
				return explode(",", $lagg['members']);
5986
			}
5987
		}
5988
	} else {
5989
		return $realif;
5990
	}
5991
}
5992

    
5993
function interface_is_wireless_clone($wlif) {
5994
	if (!stristr($wlif, "_wlan")) {
5995
		return false;
5996
	} else {
5997
		return true;
5998
	}
5999
}
6000

    
6001
function interface_get_wireless_base($wlif) {
6002
	if (!stristr($wlif, "_wlan")) {
6003
		return $wlif;
6004
	} else {
6005
		return substr($wlif, 0, stripos($wlif, "_wlan"));
6006
	}
6007
}
6008

    
6009
function interface_get_wireless_clone($wlif) {
6010
	if (!stristr($wlif, "_wlan")) {
6011
		return $wlif . "_wlan0";
6012
	} else {
6013
		return $wlif;
6014
	}
6015
}
6016

    
6017
function interface_list_wireless() {
6018
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
6019

    
6020
	$result = array();
6021
	foreach ($portlist as $port) {
6022
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
6023
			continue;
6024
		}
6025

    
6026
		$desc = $port . " ( " . get_single_sysctl(
6027
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
6028

    
6029
		$result[] = array(
6030
		    "if" => $port,
6031
		    "descr" => $desc
6032
		);
6033
	}
6034

    
6035
	return $result;
6036
}
6037

    
6038
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = false) {
6039
	global $config, $g;
6040

    
6041
	$wanif = NULL;
6042

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

    
6085
			if (empty($config['interfaces'][$interface])) {
6086
				break;
6087
			}
6088

    
6089
			$cfg = &$config['interfaces'][$interface];
6090

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

    
6149
	return $wanif;
6150
}
6151

    
6152
/* Guess the physical interface by providing a IP address */
6153
function guess_interface_from_ip($ipaddress) {
6154

    
6155
	if (!is_ipaddr($ipaddress)) {
6156
		return false;
6157
	}
6158

    
6159
	$route = route_get($ipaddress, '', true);
6160
	if (empty($route)) {
6161
		return false;
6162
	}
6163

    
6164
	if (!empty($route[0]['interface-name'])) {
6165
		return $route[0]['interface-name'];
6166
	}
6167

    
6168
	return false;
6169
}
6170

    
6171
/*
6172
 * find_ip_interface($ip): return the interface where an ip is defined
6173
 *   (or if $bits is specified, where an IP within the subnet is defined)
6174
 */
6175
function find_ip_interface($ip, $bits = null) {
6176
	if (!is_ipaddr($ip)) {
6177
		return false;
6178
	}
6179

    
6180
	$isv6ip = is_ipaddrv6($ip);
6181

    
6182
	/* if list */
6183
	$ifdescrs = get_configured_interface_list();
6184

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

    
6203
	return false;
6204
}
6205

    
6206
/*
6207
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
6208
 *   (or if $bits is specified, where an IP within the subnet is found)
6209
 */
6210
function find_virtual_ip_alias($ip, $bits = null) {
6211
	global $config;
6212

    
6213
	if (!is_array($config['virtualip']['vip'])) {
6214
		return false;
6215
	}
6216
	if (!is_ipaddr($ip)) {
6217
		return false;
6218
	}
6219

    
6220
	$isv6ip = is_ipaddrv6($ip);
6221

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

    
6242
function link_interface_to_track6($int, $action = "") {
6243
	global $config;
6244

    
6245
	if (empty($int)) {
6246
		return;
6247
	}
6248

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

    
6267
function interface_find_child_cfgmtu($realiface) {
6268
	global $config;
6269

    
6270
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
6271
	$vlans = link_interface_to_vlans($realiface);
6272
	$qinqs = link_interface_to_qinqs($realiface);
6273
	$bridge = link_interface_to_bridge($realiface);
6274
	if (!empty($interface)) {
6275
		$gifs = link_interface_to_tunnelif($interface, 'gif');
6276
		$gres = link_interface_to_tunnelif($interface, 'gre');
6277
	} else {
6278
		$gifs = array();
6279
		$gres = array();
6280
	}
6281

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

    
6343
	return $mtu;
6344
}
6345

    
6346
function link_interface_to_vlans($int, $action = "") {
6347
	global $config;
6348

    
6349
	if (empty($int)) {
6350
		return;
6351
	}
6352

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

    
6370
function link_interface_to_qinqs($int, $action = "") {
6371
	global $config;
6372

    
6373
	if (empty($int)) {
6374
		return;
6375
	}
6376

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

    
6394
function link_interface_to_vips($int, $action = "", $vhid = '') {
6395
	global $config;
6396

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

    
6424
	return NULL;
6425
}
6426

    
6427
/****f* interfaces/link_interface_to_bridge
6428
 * NAME
6429
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6430
 * INPUTS
6431
 *   $ip
6432
 * RESULT
6433
 *   bridge[0-99]
6434
 ******/
6435
function link_interface_to_bridge($int) {
6436
	global $config;
6437

    
6438
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged'])) {
6439
		foreach ($config['bridges']['bridged'] as $bridge) {
6440
			if (in_array($int, explode(',', $bridge['members']))) {
6441
				return "{$bridge['bridgeif']}";
6442
			}
6443
		}
6444
	}
6445
}
6446

    
6447
function link_interface_to_lagg($int) {
6448
	global $config;
6449

    
6450
	if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
6451
		foreach ($config['laggs']['lagg'] as $lagg) {
6452
			if (in_array($int, explode(',', $lagg['members']))) {
6453
				return "{$lagg['laggif']}";
6454
			}
6455
		}
6456
	}
6457
}
6458

    
6459
function link_interface_to_group($int) {
6460
	global $config;
6461

    
6462
	$result = array();
6463

    
6464
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
6465
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
6466
			if (in_array($int, explode(" ", $group['members']))) {
6467
				$result[$group['ifname']] = $int;
6468
			}
6469
		}
6470
	}
6471

    
6472
	return $result;
6473
}
6474

    
6475
function link_interface_to_tunnelif($interface, $type) {
6476
	global $config;
6477

    
6478
	if (!in_array($type, array('gre', 'gif'))) {
6479
		return;
6480
	}
6481

    
6482
	$result = array();
6483

    
6484
	if (is_array($config["{$type}s"][$type])) {
6485
		foreach ($config["{$type}s"][$type] as $tunnel) {
6486
			if ($tunnel['if'] == $interface) {
6487
				$result[] = $tunnel;
6488
			}
6489
		}
6490
	}
6491

    
6492
	return $result;
6493
}
6494

    
6495
/*
6496
 * find_interface_ip($interface): return the interface ip (first found)
6497
 */
6498
function find_interface_ip($interface, $flush = false) {
6499
	global $interface_ip_arr_cache;
6500
	global $interface_sn_arr_cache;
6501

    
6502
	$interface = str_replace("\n", "", $interface);
6503

    
6504
	if (!does_interface_exist($interface)) {
6505
		return;
6506
	}
6507

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

    
6529
	return $interface_ip_arr_cache[$interface];
6530
}
6531

    
6532
/*
6533
 * find_interface_ipv6($interface): return the interface ip (first found)
6534
 */
6535
function find_interface_ipv6($interface, $flush = false) {
6536
	global $interface_ipv6_arr_cache;
6537
	global $interface_snv6_arr_cache;
6538
	global $config;
6539

    
6540
	$interface = trim($interface);
6541
	$interface = get_real_interface($interface);
6542

    
6543
	if (!does_interface_exist($interface)) {
6544
		return;
6545
	}
6546

    
6547
	/* Setup IP cache */
6548
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6549
		$ifinfo = pfSense_get_interface_addresses($interface);
6550
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6551
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6552
	}
6553

    
6554
	return $interface_ipv6_arr_cache[$interface];
6555
}
6556

    
6557
/*
6558
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6559
 */
6560
function find_interface_ipv6_ll($interface, $flush = false) {
6561
	global $interface_llv6_arr_cache;
6562
	global $config;
6563

    
6564
	$interface = str_replace("\n", "", $interface);
6565

    
6566
	if (!does_interface_exist($interface)) {
6567
		return;
6568
	}
6569

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

    
6586
function find_interface_subnet($interface, $flush = false) {
6587
	global $interface_sn_arr_cache;
6588
	global $interface_ip_arr_cache;
6589

    
6590
	$interface = str_replace("\n", "", $interface);
6591
	if (does_interface_exist($interface) == false) {
6592
		return;
6593
	}
6594

    
6595
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6596
		$ifinfo = pfSense_get_interface_addresses($interface);
6597
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6598
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6599
	}
6600

    
6601
	return $interface_sn_arr_cache[$interface];
6602
}
6603

    
6604
function find_interface_subnetv6($interface, $flush = false) {
6605
	global $interface_snv6_arr_cache;
6606
	global $interface_ipv6_arr_cache;
6607

    
6608
	$interface = str_replace("\n", "", $interface);
6609
	if (does_interface_exist($interface) == false) {
6610
		return;
6611
	}
6612

    
6613
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6614
		$ifinfo = pfSense_get_interface_addresses($interface);
6615
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6616
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6617
	}
6618

    
6619
	return $interface_snv6_arr_cache[$interface];
6620
}
6621

    
6622
function ip_in_interface_alias_subnet($interface, $ipalias) {
6623
	global $config;
6624

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

    
6644
	return false;
6645
}
6646

    
6647
function get_possible_listen_ips($include_ipv6_link_local=false) {
6648

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

    
6670
	$interfaces['lo0'] = 'Localhost';
6671

    
6672
	return $interfaces;
6673
}
6674

    
6675
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6676
	global $config;
6677

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

    
6703
function get_interface_ip($interface = "wan") {
6704
	global $config;
6705

    
6706
	if (substr($interface, 0, 4) == '_vip') {
6707
		return get_configured_vip_ipv4($interface);
6708
	} elseif (substr($interface, 0, 5) == '_lloc') {
6709
		/* No link-local address for v4. */
6710
		return null;
6711
	}
6712

    
6713
	$realif = get_failover_interface($interface, 'inet');
6714
	if (!$realif) {
6715
		return null;
6716
	}
6717

    
6718
	if (substr($realif, 0, 4) == '_vip') {
6719
		return get_configured_vip_ipv4($realif);
6720
	} elseif (substr($realif, 0, 5) == '_lloc') {
6721
		/* No link-local address for v4. */
6722
		return null;
6723
	}
6724

    
6725
	if (is_array($config['interfaces'][$interface]) &&
6726
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6727
		return ($config['interfaces'][$interface]['ipaddr']);
6728
	}
6729

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

    
6743
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false) {
6744
	global $config;
6745

    
6746
	if (substr($interface, 0, 4) == '_vip') {
6747
		return get_configured_vip_ipv6($interface);
6748
	} elseif (substr($interface, 0, 5) == '_lloc') {
6749
		return get_interface_linklocal($interface);
6750
	}
6751

    
6752
	$realif = get_failover_interface($interface, 'inet6');
6753
	if (!$realif) {
6754
		return null;
6755
	}
6756

    
6757
	if (substr($realif, 0, 4) == '_vip') {
6758
		return get_configured_vip_ipv6($realif);
6759
	} elseif (substr($realif, 0, 5) == '_lloc') {
6760
		return get_interface_linklocal($realif);
6761
	}
6762

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

    
6780
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6781
	if ($config['interfaces'][$interface]['ipaddrv6'] == 'track6') {
6782
		$curip = get_interface_track6ip($interface);
6783
		if ($curip) {
6784
			return $curip[0];
6785
		}
6786
	}
6787

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

    
6811
function get_interface_linklocal($interface = "wan") {
6812

    
6813
	$realif = get_failover_interface($interface, 'inet6');
6814
	if (!$realif) {
6815
		return null;
6816
	}
6817

    
6818
	if (substr($interface, 0, 4) == '_vip') {
6819
		$realif = get_real_interface($interface);
6820
	} elseif (substr($interface, 0, 5) == '_lloc') {
6821
		$realif = get_real_interface(substr($interface, 5));
6822
	}
6823

    
6824
	$curip = find_interface_ipv6_ll($realif);
6825
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6826
		return $curip;
6827
	} else {
6828
		return null;
6829
	}
6830
}
6831

    
6832
function get_interface_track6ip($interface = "wan") {
6833
	$realif = get_real_interface($interface);
6834
	$vips = get_configured_vip_list('inet6');
6835

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

    
6853
function get_interface_subnet($interface = "wan") {
6854
	global $config;
6855

    
6856
	if (substr($interface, 0, 4) == '_vip') {
6857
		return (get_configured_vip_subnetv4($interface));
6858
	}
6859

    
6860
	if (is_array($config['interfaces'][$interface]) &&
6861
	    !empty($config['interfaces'][$interface]['subnet']) &&
6862
	    is_ipaddrv4($config['interfaces'][$interface]['ipaddr'])) {
6863
		return ($config['interfaces'][$interface]['subnet']);
6864
	}
6865

    
6866
	$realif = get_real_interface($interface);
6867
	if (!$realif) {
6868
		return (NULL);
6869
	}
6870

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

    
6876
	return (NULL);
6877
}
6878

    
6879
function get_interface_subnetv6($interface = "wan") {
6880
	global $config;
6881

    
6882
	if (substr($interface, 0, 4) == '_vip') {
6883
		return (get_configured_vip_subnetv6($interface));
6884
	} elseif (substr($interface, 0, 5) == '_lloc') {
6885
		$interface = substr($interface, 5);
6886
	}
6887

    
6888
	if (is_array($config['interfaces'][$interface]) &&
6889
	    !empty($config['interfaces'][$interface]['subnetv6']) &&
6890
	    is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6891
		return ($config['interfaces'][$interface]['subnetv6']);
6892
	}
6893

    
6894
	$realif = get_real_interface($interface, 'inet6');
6895
	if (!$realif) {
6896
		return (NULL);
6897
	}
6898

    
6899
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6900
	if ($config['interfaces'][$interface]['ipaddrv6'] == 'track6') {
6901
		$curip = get_interface_track6ip($interface);
6902
		if ($curip) {
6903
			return $curip[1];
6904
		}
6905
	}
6906

    
6907
	$cursn = find_interface_subnetv6($realif);
6908
	if (!empty($cursn)) {
6909
		return ($cursn);
6910
	}
6911

    
6912
	return (NULL);
6913
}
6914

    
6915
/* return outside interfaces with a gateway */
6916
function get_interfaces_with_gateway() {
6917
	global $config;
6918

    
6919
	$ints = array();
6920

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

    
6943
				break;
6944
		}
6945
	}
6946
	return $ints;
6947
}
6948

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

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

    
6987
	return false;
6988
}
6989

    
6990
/* return true if interface has a gateway */
6991
function interface_has_gatewayv6($friendly) {
6992
	global $config;
6993

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

    
7022
	return false;
7023
}
7024

    
7025
/****f* interfaces/is_altq_capable
7026
 * NAME
7027
 *   is_altq_capable - Test if interface is capable of using ALTQ
7028
 * INPUTS
7029
 *   $int            - string containing interface name
7030
 * RESULT
7031
 *   boolean         - true or false
7032
 ******/
7033

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

    
7049
	$int_family = remove_ifindex($int);
7050

    
7051
	if (in_array($int_family, $capable)) {
7052
		return true;
7053
	} elseif (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
7054
		return true;
7055
	} elseif (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
7056
		return true;
7057
	} elseif (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
7058
		return true;
7059
	} else {
7060
		return false;
7061
	}
7062
}
7063

    
7064
/****f* interfaces/is_interface_wireless
7065
 * NAME
7066
 *   is_interface_wireless - Returns if an interface is wireless
7067
 * RESULT
7068
 *   $tmp       - Returns if an interface is wireless
7069
 ******/
7070
function is_interface_wireless($interface) {
7071
	global $config, $g;
7072

    
7073
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
7074
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
7075
		if (preg_match($g['wireless_regex'], $interface)) {
7076
			if (isset($config['interfaces'][$friendly])) {
7077
				$config['interfaces'][$friendly]['wireless'] = array();
7078
			}
7079
			return true;
7080
		}
7081
		return false;
7082
	} else {
7083
		return true;
7084
	}
7085
}
7086

    
7087
function get_wireless_modes($interface) {
7088
	/* return wireless modes and channels */
7089
	$wireless_modes = array();
7090

    
7091
	$cloned_interface = get_real_interface($interface);
7092

    
7093
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7094
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
7095
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\\n\" \$3 }'";
7096
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
7097

    
7098
		$interface_channels = "";
7099
		exec("$chan_list | $stack_list | sort -u | $format_list 2>&1", $interface_channels);
7100
		$interface_channel_count = count($interface_channels);
7101

    
7102
		$c = 0;
7103
		while ($c < $interface_channel_count) {
7104
			$channel_line = explode(",", $interface_channels["$c"]);
7105
			$wireless_mode = trim($channel_line[0]);
7106
			$wireless_channel = trim($channel_line[1]);
7107
			if (trim($wireless_mode) != "") {
7108
				/* if we only have 11g also set 11b channels */
7109
				if ($wireless_mode == "11g") {
7110
					if (!isset($wireless_modes["11b"])) {
7111
						$wireless_modes["11b"] = array();
7112
					}
7113
				} elseif ($wireless_mode == "11g ht") {
7114
					if (!isset($wireless_modes["11b"])) {
7115
						$wireless_modes["11b"] = array();
7116
					}
7117
					if (!isset($wireless_modes["11g"])) {
7118
						$wireless_modes["11g"] = array();
7119
					}
7120
					$wireless_mode = "11ng";
7121
				} elseif ($wireless_mode == "11a ht") {
7122
					if (!isset($wireless_modes["11a"])) {
7123
						$wireless_modes["11a"] = array();
7124
					}
7125
					$wireless_mode = "11na";
7126
				}
7127
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
7128
			}
7129
			$c++;
7130
		}
7131
	}
7132
	return($wireless_modes);
7133
}
7134

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

    
7140
		$interface_channels = "";
7141
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7142
		return $interface_channels;
7143
}
7144

    
7145
/* return wireless HT modes */
7146
function get_wireless_ht_modes($interface) {
7147
	$wireless_hts_supported = array(0 => gettext('Auto'));
7148

    
7149
	$cloned_interface = get_real_interface($interface);
7150

    
7151
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7152
		$interface_channels = get_wireless_channels($cloned_interface);
7153

    
7154
		foreach ($interface_channels as $channel) {
7155
			$channel_line = explode(",", $channel);
7156
			$wireless_ht = trim($channel_line[1]);
7157
			if (!empty($wireless_ht)) {
7158
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
7159
			}
7160
		}
7161
	}
7162
	return($wireless_hts_supported);
7163
}
7164

    
7165
/* return wireless HT by channel/standard */
7166
function get_wireless_ht_list($interface) {
7167
	$wireless_hts = array();
7168

    
7169
	$cloned_interface = get_real_interface($interface);
7170

    
7171
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7172
		$interface_channels = get_wireless_channels($cloned_interface);
7173
		$interface_channel_count = count($interface_channels);
7174

    
7175
		$c = 0;
7176
		while ($c < $interface_channel_count) {
7177
			$channel_line = explode(",", $interface_channels["$c"]);
7178
			$wireless_mode = trim($channel_line[0]);
7179
			$wireless_ht = trim($channel_line[1]);
7180
			$wireless_channel = trim($channel_line[2]);
7181
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
7182
				if ($wireless_mode == "11g") {
7183
					if (!isset($wireless_modes["11g"])) {
7184
						$wireless_hts["11g"] = array();
7185
					}
7186
					$wireless_mode = "11ng";
7187
				} elseif ($wireless_mode == "11a") {
7188
					if (!isset($wireless_modes["11a"])) {
7189
						$wireless_hts["11a"] = array();
7190
					}
7191
					$wireless_mode = "11na";
7192
				}
7193
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
7194
			}
7195
			$c++;
7196
		}
7197
	}
7198
	return($wireless_hts);
7199
}
7200

    
7201
/* return channel numbers, frequency, max txpower, and max regulation txpower */
7202
function get_wireless_channel_info($interface) {
7203
	$wireless_channels = array();
7204

    
7205
	$cloned_interface = get_real_interface($interface);
7206

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

    
7212
		$interface_channels = "";
7213
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7214

    
7215
		foreach ($interface_channels as $channel_line) {
7216
			$channel_line = explode(",", $channel_line);
7217
			if (!isset($wireless_channels[$channel_line[0]])) {
7218
				$wireless_channels[$channel_line[0]] = $channel_line;
7219
			}
7220
		}
7221
	}
7222
	return($wireless_channels);
7223
}
7224

    
7225
function set_interface_mtu($interface, $mtu) {
7226

    
7227
	/* LAGG interface must be destroyed and re-created to change MTU */
7228
	if ((substr($interface, 0, 4) == 'lagg') &&
7229
	    (!strstr($interface, "."))) {
7230
		if (isset($config['laggs']['lagg']) &&
7231
		    is_array($config['laggs']['lagg'])) {
7232
			foreach ($config['laggs']['lagg'] as $lagg) {
7233
				if ($lagg['laggif'] == $interface) {
7234
					interface_lagg_configure($lagg);
7235
					break;
7236
				}
7237
			}
7238
		}
7239
	} else {
7240
		pfSense_interface_mtu($interface, $mtu);
7241
		set_ipv6routes_mtu($interface, $mtu);
7242
	}
7243
}
7244

    
7245
/****f* interfaces/get_interface_mtu
7246
 * NAME
7247
 *   get_interface_mtu - Return the mtu of an interface
7248
 * RESULT
7249
 *   $tmp       - Returns the mtu of an interface
7250
 ******/
7251
function get_interface_mtu($interface) {
7252
	$mtu = pfSense_interface_getmtu($interface);
7253
	return $mtu['mtu'];
7254
}
7255

    
7256
function get_interface_mac($interface) {
7257
	$macinfo = pfSense_get_interface_addresses($interface);
7258
	return $macinfo["macaddr"];
7259
}
7260

    
7261
function get_interface_vendor_mac($interface) {
7262
	global $config, $g;
7263

    
7264
	$macinfo = pfSense_get_interface_addresses($interface);
7265
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7266
	    "00:00:00:00:00:00") {
7267
		return ($macinfo["hwaddr"]);
7268
	}
7269

    
7270
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7271
	if (file_exists($hwaddr_file)) {
7272
		$macaddr = trim(file_get_contents($hwaddr_file));
7273
		if (is_macaddr($macaddr)) {
7274
			return ($macaddr);
7275
		}
7276
	} elseif (is_macaddr($macinfo['macaddr'])) {
7277
		/* Save original macaddress to be restored when necessary */
7278
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7279
	}
7280

    
7281
	return (NULL);
7282
}
7283

    
7284
/****f* pfsense-utils/generate_random_mac_address
7285
 * NAME
7286
 *   generate_random_mac - generates a random mac address
7287
 * INPUTS
7288
 *   none
7289
 * RESULT
7290
 *   $mac - a random mac address
7291
 ******/
7292
function generate_random_mac_address() {
7293
	$mac = "02";
7294
	for ($x = 0; $x < 5; $x++) {
7295
		$mac .= ":" . dechex(rand(16, 255));
7296
	}
7297
	return $mac;
7298
}
7299

    
7300
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7301
	global $g;
7302

    
7303
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7304

    
7305
	if (!empty($iface) && !empty($pppif)) {
7306
		$cron_cmd = <<<EOD
7307
#!/bin/sh
7308
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7309
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7310

    
7311
EOD;
7312

    
7313
		@file_put_contents($cron_file, $cron_cmd);
7314
		chmod($cron_file, 0755);
7315
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7316
	} else {
7317
		unlink_if_exists($cron_file);
7318
	}
7319
}
7320

    
7321
function get_interface_default_mtu($type = "ethernet") {
7322
	switch ($type) {
7323
		case "gre":
7324
			return 1476;
7325
			break;
7326
		case "gif":
7327
			return 1280;
7328
			break;
7329
		case "tun":
7330
		case "vlan":
7331
		case "tap":
7332
		case "ethernet":
7333
		default:
7334
			return 1500;
7335
			break;
7336
	}
7337

    
7338
	/* Never reached */
7339
	return 1500;
7340
}
7341

    
7342
function get_vip_descr($ipaddress) {
7343
	global $config;
7344

    
7345
	foreach ($config['virtualip']['vip'] as $vip) {
7346
		if ($vip['subnet'] == $ipaddress) {
7347
			return ($vip['descr']);
7348
		}
7349
	}
7350
	return "";
7351
}
7352

    
7353
function interfaces_staticarp_configure($if) {
7354
	global $config, $g;
7355
	if (isset($config['system']['developerspew'])) {
7356
		$mt = microtime();
7357
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7358
	}
7359

    
7360
	$ifcfg = $config['interfaces'][$if];
7361

    
7362
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
7363
		return 0;
7364
	}
7365

    
7366
	/* Enable staticarp, if enabled */
7367
	if (isset($config['dhcpd'][$if]['staticarp'])) {
7368
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7369
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7370
	} else {
7371
		/*
7372
		 * Interfaces do not have staticarp enabled by default
7373
		 * Let's not disable staticarp on freshly created interfaces
7374
		 */
7375
		if (!platform_booting()) {
7376
			mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7377
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7378
		}
7379
	}
7380

    
7381
	/* Enable static arp entries */
7382
	if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
7383
		foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
7384
			if (empty($arpent['ipaddr']) || empty($arpent['mac'])) {
7385
				continue;
7386
			}
7387
			if (isset($config['dhcpd'][$if]['staticarp']) || isset($arpent['arp_table_static_entry'])) {
7388
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7389
			}
7390
		}
7391
	}
7392

    
7393
	return 0;
7394
}
7395

    
7396
function get_failover_interface($interface, $family = "all") {
7397
	global $config;
7398

    
7399
	/* shortcut to get_real_interface if we find it in the config */
7400
	if (is_array($config['interfaces'][$interface])) {
7401
		return get_real_interface($interface, $family);
7402
	}
7403

    
7404
	/* compare against gateway groups */
7405
	$a_groups = return_gateway_groups_array(true);
7406
	if (is_array($a_groups[$interface])) {
7407
		/* we found a gateway group, fetch the interface or vip */
7408
		if (!empty($a_groups[$interface][0]['vip'])) {
7409
			return $a_groups[$interface][0]['vip'];
7410
		} else {
7411
			return $a_groups[$interface][0]['int'];
7412
		}
7413
	}
7414
	/* fall through to get_real_interface */
7415
	/* XXX: Really needed? */
7416
	return get_real_interface($interface, $family);
7417
}
7418

    
7419
/****f* interfaces/interface_has_dhcp
7420
 * NAME
7421
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7422
 * INPUTS
7423
 *   interface or gateway group name
7424
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7425
 * RESULT
7426
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7427
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7428
 ******/
7429
function interface_has_dhcp($interface, $family = 4) {
7430
	global $config;
7431

    
7432
	if ($config['interfaces'][$interface]) {
7433
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
7434
			return true;
7435
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
7436
			return true;
7437
		} else {
7438
			return false;
7439
		}
7440
	}
7441

    
7442
	if (!is_array($config['gateways']['gateway_group'])) {
7443
		return false;
7444
	}
7445

    
7446
	if ($family == 6) {
7447
		$dhcp_string = "_DHCP6";
7448
	} else {
7449
		$dhcp_string = "_DHCP";
7450
	}
7451

    
7452
	foreach ($config['gateways']['gateway_group'] as $group) {
7453
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7454
			continue;
7455
		}
7456
		foreach ($group['item'] as $item) {
7457
			$item_data = explode("|", $item);
7458
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7459
				return true;
7460
			}
7461
		}
7462
	}
7463

    
7464
	return false;
7465
}
7466

    
7467
function remove_ifindex($ifname) {
7468
	return preg_replace("/[0-9]+$/", "", $ifname);
7469
}
7470

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

    
7474
	$viplist = get_configured_vip_list($family, $type);
7475
	foreach ($viplist as $vip => $address) {
7476
		$interfaces[$vip] = $address;
7477
		if ($type = VIP_CARP) {
7478
			$vip = get_configured_vip($vipid);
7479
			if (isset($vip) && is_array($vip) ) {
7480
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7481
			}
7482
		}
7483
		if (get_vip_descr($address)) {
7484
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
7485
		}
7486
	}
7487
	return $interfaces;
7488
}
7489

    
7490
function return_gateway_groups_array_with_descr() {
7491
	$interfaces = array();
7492
	$grouplist = return_gateway_groups_array();
7493
	foreach ($grouplist as $name => $group) {
7494
		if ($group[0]['vip'] != "") {
7495
			$vipif = $group[0]['vip'];
7496
		} else {
7497
			$vipif = $group[0]['int'];
7498
		}
7499

    
7500
		$interfaces[$name] = "GW Group {$name}";
7501
	}
7502
	return $interfaces;
7503
}
7504

    
7505
function get_serial_ports() {
7506
	$linklist = array();
7507
	if (!is_dir("/var/spool/lock")) {
7508
		mwexec("/bin/mkdir -p /var/spool/lock");
7509
	}
7510
	$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);
7511
	foreach ($serialports as $port) {
7512
		$linklist[$port] = trim($port);
7513
	}
7514
	return $linklist;
7515
}
7516

    
7517
function get_interface_ports() {
7518
	global $config;
7519
	$linklist = array();
7520
	$portlist = get_interface_list();
7521
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
7522
		foreach ($config['vlans']['vlan'] as $vlan) {
7523
			$portlist[$vlan['vlanif']] = $vlan;
7524
		}
7525
	}
7526

    
7527
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
7528
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
7529
			$members = explode(" ", $qinq['members']);
7530
			foreach ($members as $mem) {
7531
				$qentry = $qinq['vlanif'] . "." . $mem;
7532
				$portlist[$qentry] = $qentry;
7533
			}
7534
		}
7535
	}
7536

    
7537
	foreach ($portlist as $ifn => $ifinfo) {
7538
		$string = "";
7539
		if (is_array($ifinfo)) {
7540
			$string .= $ifn;
7541
			if ($ifinfo['mac']) {
7542
				$string .= " ({$ifinfo['mac']})";
7543
			}
7544
			if ($ifinfo['friendly']) {
7545
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7546
			} elseif ($ifinfo['descr']) {
7547
				$string .= " - {$ifinfo['descr']}";
7548
			}
7549
		} else {
7550
			$string .= $ifinfo;
7551
		}
7552

    
7553
		$linklist[$ifn] = $string;
7554
	}
7555
	return $linklist;
7556
}
7557

    
7558
function build_ppps_link_list() {
7559
	global $pconfig;
7560

    
7561
	$linklist = array('list' => array(), 'selected' => array());
7562

    
7563
	if ($pconfig['type'] == 'ppp') {
7564
		$linklist['list'] = get_serial_ports();
7565
	} else {
7566
		$iflist = get_interface_ports();
7567

    
7568
		$viplist = array();
7569
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7570
		foreach ($carplist as $vid => $vaddr) {
7571
			$vip = get_configured_vip($vid);
7572
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7573
		}
7574

    
7575
		$linklist['list'] = array_merge($iflist, $viplist);
7576

    
7577
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7578
		$lagglist = get_lagg_interface_list();
7579
		foreach ($lagglist as $laggif => $lagg) {
7580
			/* LAGG members cannot be assigned */
7581
			$laggmembers = explode(',', $lagg['members']);
7582
			foreach ($laggmembers as $lagm) {
7583
				if (isset($linklist['list'][$lagm])) {
7584
					unset($linklist['list'][$lagm]);
7585
				}
7586
			}
7587
		}
7588
	}
7589

    
7590
	$selected_ports = array();
7591
	if (is_array($pconfig['interfaces'])) {
7592
		$selected_ports = $pconfig['interfaces'];
7593
	} elseif (!empty($pconfig['interfaces'])) {
7594
		$selected_ports = explode(',', $pconfig['interfaces']);
7595
	}
7596
	foreach ($selected_ports as $port) {
7597
		if (isset($linklist['list'][$port])) {
7598
			array_push($linklist['selected'], $port);
7599
		}
7600
	}
7601
	return($linklist);
7602
}
7603

    
7604
function create_interface_list() {
7605
	global $config;
7606

    
7607
	$iflist = array();
7608

    
7609
	// add group interfaces
7610
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
7611
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
7612
			if (have_ruleint_access($ifgen['ifname'])) {
7613
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7614
			}
7615
		}
7616
	}
7617

    
7618
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7619
		if (have_ruleint_access($ifent)) {
7620
			$iflist[$ifent] = $ifdesc;
7621
		}
7622
	}
7623

    
7624
	if ($config['l2tp']['mode'] == "server" && have_ruleint_access("l2tp")) {
7625
		$iflist['l2tp'] = gettext('L2TP VPN');
7626
	}
7627

    
7628
	if (is_pppoe_server_enabled() && have_ruleint_access("pppoe")) {
7629
		$iflist['pppoe'] = gettext("PPPoE Server");
7630
	}
7631

    
7632
	// add ipsec interfaces
7633
	if (ipsec_enabled() && have_ruleint_access("enc0")) {
7634
		$iflist["enc0"] = gettext("IPsec");
7635
	}
7636

    
7637
	// add openvpn/tun interfaces
7638
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7639
		$iflist["openvpn"] = gettext("OpenVPN");
7640
	}
7641

    
7642
	if (is_wg_enabled() && have_ruleint_access("wireguard")) {
7643
		$iflist['wireguard'] = 'WireGuard';
7644
	}
7645

    
7646
	return($iflist);
7647
}
7648

    
7649
function is_pseudo_interface($inf, $tap=true) {
7650
	global $config;
7651
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe', 'wg');
7652
	foreach ($psifs as $pif) {
7653
		if (substr($inf, 0, strlen($pif)) == $pif) {
7654
			if (($pif == 'ovpn') && $tap) {
7655
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7656
				$type = ($m[1] == 'c') ? 'client' : 'server';
7657
				foreach ($config['openvpn']['openvpn-'.$type] as $ovpn) {
7658
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7659
						return false;
7660
					} elseif ($ovpn['vpnid'] == $m[2]) {
7661
						return true;
7662
					}
7663
				}
7664
			} else {
7665
				return true;
7666
			}
7667
		}
7668
	}
7669
	return false;
7670
}
7671

    
7672
function is_stf_interface($inf) {
7673
	global $config;
7674

    
7675
	if (is_array($config['interfaces'][$inf]) &&
7676
	    (($config['interfaces'][$inf]['ipaddrv6'] == '6rd') ||
7677
	    ($config['interfaces'][$inf]['ipaddrv6'] == '6to4'))) {
7678
	    return true;
7679
	}
7680

    
7681
	return false;
7682
}
7683

    
7684
?>
(22-22/61)