Project

General

Profile

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

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

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

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

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

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

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

    
63
	return true;
64
}
65

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

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

    
77
	return $interface_arr_cache;
78
}
79

    
80
/*
81
 * does_interface_exist($interface): return true or false if a interface is
82
 * detected.
83
 */
84
function does_interface_exist($interface, $flush = false) {
85
	if (!$interface) {
86
		return false;
87
	}
88

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

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

    
106

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

    
122
	$ifacedata = pfSense_getall_interface_addresses($realif);
123

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

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

    
140
	return false;
141
}
142

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

    
157
function vlan_valid_tag($tag = NULL) {
158

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

    
166
function qinq_inuse($qinq = NULL, $inqtag = NULL) {
167
        global $config;
168

    
169
	if ($qinq == NULL || $inqtag == NULL ||
170
	    !is_array($qinq) || !vlan_valid_tag($inqtag)) {
171
		return (false);
172
	}
173

    
174
        $iflist = get_configured_interface_list(true);
175
        foreach ($iflist as $if) {
176
                if ($config['interfaces'][$if]['if'] == qinq_interface($qinq, $inqtag)) {
177
                        return (true);
178
                }
179
        }
180

    
181
        return (false);
182
}
183

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

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

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

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

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

    
220
	return (NULL);
221
}
222

    
223
function vlan_inuse($vlan) {
224
	global $config;
225

    
226
	if ($vlan == NULL || !is_array($vlan)) {
227
		return (false);
228
	}
229

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

    
237
	return (false);
238
}
239

    
240
function interface_is_vlan($if = NULL) {
241
	if ($if == NULL || empty($if) || is_array($if)) {
242
		return (NULL);
243
	}
244

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

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

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

    
267
	return (NULL);
268
}
269

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

    
278
function interface_set_macaddr($interface, $mac_addr) {
279
	if (empty($mac_addr) || !is_macaddr($mac_addr)) {
280
		return;
281
	}
282

    
283
	$current_mac = get_interface_mac($interface);
284

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

    
297
function interface_is_parent($if, $parent_check) {
298

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

    
320
function interface_has_clones($if) {
321
	global $config;
322

    
323
	/* Check LAGGs. */
324
	if (isset($config['laggs']) && isset($config['laggs']['lagg']) &&
325
	    is_array($config['laggs']['lagg'])) {
326
		foreach ($config['laggs']['lagg'] as $lagg) {
327
			if (interface_is_parent($lagg['laggif'], $if)) {
328
				return (TRUE);
329
			}
330
		}
331
	}
332
	/* Check VLANs. */
333
	if (isset($config['vlans']) && isset($config['vlans']['vlan']) &&
334
	    is_array($config['vlans']['vlan'])) {
335
		foreach ($config['vlans']['vlan'] as $vlan) {
336
			if (interface_is_parent($vlan['if'], $if)) {
337
				return (TRUE);
338
			}
339
		}
340
	}
341
	/* Check bridges. */
342
	if (isset($config['bridges']) && isset($config['bridges']['bridged']) &&
343
	    is_array($config['bridges']['bridged'])) {
344
		foreach ($config['bridges']['bridged'] as $bridge) {
345
			$members = explode(',', $bridge['members']);
346
			foreach ($members as $member) {
347
				if (interface_is_parent($member, $if)) {
348
					return (TRUE);
349
				}
350
			}
351
		}
352
	}
353

    
354
	return (FALSE);
355
}
356

    
357
function interfaces_vlan_configure($parentif = "") {
358
	$dhcp6c_list = array();
359

    
360
	$vlans = config_get_path('vlans/vlan');
361
	if (is_array($vlans) && count($vlans)) {
362
		if (platform_booting()) {
363
			echo gettext("Configuring VLAN interfaces...");
364
		}
365
		foreach ($vlans as $vlan) {
366
			if (empty($vlan['vlanif'])) {
367
				$vlan['vlanif'] = vlan_interface($vlan);
368
			}
369
			if (!empty($parentif) && ($parentif != $vlan['if'])) {
370
				continue;
371
			}
372
			/* configure dhcp6 enabled VLAN interfaces later
373
			 * see https://redmine.pfsense.org/issues/3965 */
374
			$if = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
375
			if (config_get_path("interfaces/{$if}/ipaddrv6", "") == "dhcp6") {
376
				$dhcp6c_list[$if] = $vlan;
377
				continue;
378
			}
379

    
380
			/* XXX: Maybe we should report any errors?! */
381
			interface_vlan_configure($vlan, false);
382
		}
383
		foreach ($dhcp6c_list as $if => $vlan) {
384
			interface_vlan_configure($vlan, false);
385
		}
386
		/* Invalidate cache */
387
		get_interface_arr(true);
388
		if (platform_booting()) {
389
			echo gettext("done.") . "\n";
390
		}
391
	}
392
}
393

    
394
function interface_vlan_configure(&$vlan, $flush = true) {
395
	if (!is_array($vlan)) {
396
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
397
		return(NULL);
398
	}
399
	$if = $vlan['if'];
400
	if (empty($if)) {
401
		log_error(gettext("interface_vlan_configure called with if undefined."));
402
		return(NULL);
403
	}
404

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

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

    
418
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
419
		pfSense_interface_destroy($vlanif);
420
	}
421

    
422
	$tmpvlanif = pfSense_interface_create2("vlan");
423
	pfSense_interface_rename($tmpvlanif, $vlanif);
424
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
425

    
426
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
427

    
428
	interfaces_bring_up($vlanif);
429

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

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

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

    
446
	if (interface_vlan_mtu_configured($vlanif)) {
447
		set_interface_mtu($vlanif, interface_vlan_mtu_configured($vlanif));
448
	}
449

    
450
	return $vlanif;
451
}
452

    
453
/*
454
 * reconfigure VLAN childs interfaces after MTU changes, see
455
 * https://redmine.pfsense.org/issues/11035
456
 */
457
function interfaces_vlan_configure_mtu($parentif = "") {
458
	global $config;
459

    
460
	init_config_arr(array('ppps', 'ppp'));
461
	if (!is_array($config['vlans']['vlan']) ||
462
	    !count($config['vlans']['vlan'])) {
463
		return;
464
	}
465

    
466
	foreach ($config['vlans']['vlan'] as $vlan) {
467
		if ($parentif != $vlan['if']) {
468
			continue;
469
		}
470
		if (interface_vlan_mtu_configured($vlan['vlanif'])) {
471
		       set_interface_mtu($vlan['vlanif'],
472
			   interface_vlan_mtu_configured($vlan['vlanif']));
473
		}
474
		if (empty($config['ppps']['ppp'])) {
475
			continue;
476
		}
477
		// PPP interfaces must be restarted to adjust MTU changes
478
		foreach (config_get_path('ppps/ppp') as $ppp) {
479
			$ports = explode(',', $ppp['ports']);
480
			foreach ($ports as $port) {
481
				if ($port != $vlan['vlanif']) {
482
					continue;
483
				}
484
				$confif = convert_real_interface_to_friendly_interface_name($ppp['if']);
485
				interface_configure($confif);
486
			}
487
		}
488
	}
489
}
490

    
491
function interface_qinq_configure(&$qinq, $fd = NULL, $flush = true) {
492
	global $g;
493

    
494
	if (!is_array($qinq)) {
495
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
496
		return;
497
	}
498

    
499
	$qinqif = $qinq['if'];
500
	if (empty($qinqif)) {
501
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
502
		return;
503
	}
504

    
505
	if (!does_interface_exist($qinqif)) {
506
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
507
		return;
508
	}
509

    
510
	$vlanif = interface_vlan_configure($qinq);
511
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
512
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
513
		return;
514
	}
515

    
516
	if ($fd == NULL) {
517
		$exec = true;
518
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
519
	} else {
520
		$exec = false;
521
	}
522
	/* make sure the parent is converted to ng_vlan(4) and is up */
523
	interfaces_bring_up($qinqif);
524

    
525
	$ngif = str_replace(".", "_", $vlanif);
526
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
527
		exec("/usr/sbin/ngctl shutdown {$ngif}qinq: > /dev/null 2>&1");
528
		exec("/usr/sbin/ngctl msg {$ngif}qinq: gettable > /dev/null 2>&1", $result);
529
		if (empty($result)) {
530
			fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
531
			fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
532
			fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
533
		}
534
	} else {
535
		fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
536
		fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
537
		fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
538
	}
539

    
540
	/* invalidate interface cache */
541
	if ($flush) {
542
		get_interface_arr(true);
543
	}
544

    
545
	if (interface_is_vlan($qinqif) == NULL) {
546
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
547
	}
548

    
549
	$macaddr = get_interface_mac($qinqif);
550
	if (!empty($qinq['members'])) {
551
		$qinqcmdbuf = "";
552
		$members = explode(" ", $qinq['members']);
553
		foreach ($members as $qtag) {
554
			$qinq2 = array();
555
			$qinq2['tag'] = $qtag;
556
			$qinq2['if'] = $vlanif;
557
			interface_qinq2_configure($qinq2, $qinqcmdbuf, $macaddr,
558
			    false);
559
			unset($qinq2);
560
		}
561
		if (strlen($qinqcmdbuf) > 0) {
562
			fwrite($fd, $qinqcmdbuf);
563
		}
564
	}
565
	if ($exec == true) {
566
		fclose($fd);
567
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd > /dev/null 2>&1");
568
	}
569

    
570
	interfaces_bring_up($qinqif);
571
	if (!empty($qinq['members'])) {
572
		$members = explode(" ", $qinq['members']);
573
		foreach ($members as $qtag) {
574
			interfaces_bring_up(qinq_interface($qinq, $qtag));
575
		}
576
	}
577

    
578
	return $vlanif;
579
}
580

    
581
function interfaces_qinq_configure($ovpn=false) {
582
	$qinqentry = config_get_path('qinqs/qinqentry');
583
	if (is_array($qinqentry) && count($qinqentry)) {
584
		if (platform_booting() && $ovpn) {
585
			echo gettext("Configuring OpenVPN QinQ interfaces...");
586
		} elseif (platform_booting()) {
587
			echo gettext("Configuring QinQ interfaces...");
588
		}
589
		foreach ($qinqentry as $qinq) {
590
			if (($ovpn && strstr($qinq['if'], "ovpn")) ||
591
			    (!$ovpn && !strstr($qinq['if'], "ovpn"))) {
592
				interface_qinq_configure($qinq, NULL, false);
593
			}
594
		}
595
		/* Invalidate cache */
596
		get_interface_arr(true);
597
		if (platform_booting()) {
598
			echo gettext("done.") . "\n";
599
		}
600
	}
601
}
602

    
603
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr, $flush = true) {
604
	if (!is_array($qinq)) {
605
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
606
		return;
607
	}
608

    
609
	$if = $qinq['if'];
610
	if (empty($if)) {
611
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
612
		return;
613
	}
614
	$tag = $qinq['tag'];
615
	$vlanif = "{$if}.{$tag}";
616
	$ngif = str_replace(".", "_", $if);
617
	if (strlen($vlanif) > IF_NAMESIZE) {
618
		log_error(sprintf(gettext("interface_qinq2_configure interface name too big %s. (max. size: %d).%s"),
619
		    $vlanif, IF_NAMESIZE, "\n"));
620
		return;
621
	}
622

    
623
	exec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1");
624
	$cmdbuf .= "mkpeer {$ngif}qinq: eiface {$ngif}{$tag} ether\n";
625
	$cmdbuf .= "name {$ngif}qinq:{$ngif}{$tag} {$ngif}h{$tag}\n";
626
	$cmdbuf .= "msg {$ngif}qinq: addfilter { vlan={$tag} hook=\"{$ngif}{$tag}\" }\n";
627
	$cmdbuf .= "msg {$ngif}h{$tag}: setifname \"{$vlanif}\"\n";
628
	$cmdbuf .= "msg {$ngif}h{$tag}: set {$macaddr}\n";
629

    
630
	/* invalidate interface cache */
631
	if ($flush) {
632
		get_interface_arr(true);
633
	}
634

    
635
	return $vlanif;
636
}
637

    
638
function interfaces_create_wireless_clones() {
639
	global $config;
640

    
641
	$iflist = get_configured_interface_list();
642

    
643
	foreach ($iflist as $if) {
644
		$realif = $config['interfaces'][$if]['if'];
645
		if (!is_interface_wireless($realif)) {
646
			continue;
647
		}
648
		interface_wireless_clone(interface_get_wireless_clone($realif),
649
		    $config['interfaces'][$if]);
650
	}
651

    
652
	$wclone = config_get_path('wireless/clone');
653
	if (is_array($wclone) && count($wclone)) {
654
		if (platform_booting()) {
655
			echo gettext("Creating wireless clone interfaces...");
656
		}
657
		/* Invalidate cache */
658
		get_interface_arr(true);
659
		foreach ($wclone as $clone) {
660
			if (empty($clone['cloneif'])) {
661
				continue;
662
			}
663
			if (does_interface_exist($clone['cloneif'])) {
664
				continue;
665
			}
666
			/* XXX: Maybe we should report any errors?! */
667
			interface_wireless_clone($clone['cloneif'], $clone);
668
		}
669
		if (platform_booting()) {
670
			echo gettext("done.") . "\n";
671
		}
672
	}
673
}
674

    
675
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
676
	global $config;
677

    
678
	$bridged = config_get_path('bridges/bridged');
679
	if (!is_array($bridged) || !count($bridged)) {
680
		return;
681
	}
682

    
683
	$i = 0;
684
	foreach ($bridged as $bridge) {
685
		if (empty($bridge['bridgeif'])) {
686
			$bridge['bridgeif'] = "bridge{$i}";
687
		}
688
		if (!empty($realif) && ($realif != $bridge['bridgeif'])) {
689
			continue;
690
		}
691
		$ifname = false;
692
		foreach ($config['interfaces'] as $intname => $intpar) {
693
			if ($intpar['if'] == $bridge['bridgeif']) {
694
				$ifname = $intname;
695
				break;
696
			}
697
		}
698

    
699
		if ($ifname && (config_get_path("interfaces/{$ifname}/ipaddrv6", "") == "track6")) {
700
			if ($checkmember == 1) {
701
				continue;
702
			} else {
703
				$checkmember = 0;
704
			}
705
		} elseif (($checkmember == 2) && !$ifname) {
706
			continue;
707
		}
708

    
709
		/* XXX: Maybe we should report any errors?! */
710
		interface_bridge_configure($bridge, $checkmember, false);
711
		$i++;
712
	}
713

    
714
	/* Invalidate cache */
715
	get_interface_arr(true);
716
}
717

    
718
function interface_bridge_configure(&$bridge, $checkmember = 0, $flush = true) {
719
	if (!is_array($bridge)) {
720
		return;
721
	}
722

    
723
	if (empty($bridge['members'])) {
724
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
725
		return;
726
	}
727

    
728
	$members = explode(',', $bridge['members']);
729
	if (!count($members)) {
730
		return;
731
	}
732

    
733
	/* Calculate smaller mtu and enforce it */
734
	$smallermtu = 0;
735
	$foundgif = false;
736
	foreach ($members as $member) {
737
		$realif = get_real_interface($member);
738
		$mtu = get_interface_mtu($realif);
739
		if (substr($realif, 0, 3) == "gif") {
740
			$foundgif = true;
741
			if ($checkmember == 1) {
742
				return;
743
			}
744
			if ($mtu <= 1500) {
745
				continue;
746
			}
747
		}
748
		if ($smallermtu == 0 && !empty($mtu)) {
749
			$smallermtu = $mtu;
750
		} elseif (!empty($mtu) && $mtu < $smallermtu) {
751
			$smallermtu = $mtu;
752
		}
753
	}
754
	if ($foundgif == false && $checkmember == 2) {
755
		return;
756
	}
757

    
758
	/* Just in case anything is not working well */
759
	if ($smallermtu == 0) {
760
		$smallermtu = 1500;
761
	}
762

    
763
	if (!empty($bridge['bridgeif'])) {
764
		pfSense_interface_destroy($bridge['bridgeif']);
765
		pfSense_interface_create2($bridge['bridgeif']);
766
		$bridgeif = escapeshellarg($bridge['bridgeif']);
767
	} else {
768
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
769
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
770
		$bridgeif = pfSense_interface_create2("bridge");
771
		$bridge['bridgeif'] = $bridgeif;
772
	}
773

    
774
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
775
	if ($bridgemtu > $smallermtu) {
776
		$smallermtu = $bridgemtu;
777
	}
778

    
779
	$checklist = get_configured_interface_list();
780

    
781
	/* Add interfaces to bridge */
782
	foreach ($members as $member) {
783
		if (empty($checklist[$member])) {
784
			continue;
785
		}
786
		$realif = get_real_interface($member);
787
		if (!$realif) {
788
			log_error(gettext("realif not defined in interfaces bridge - up"));
789
			continue;
790
		}
791
		/* make sure the parent interface is up */
792
		pfSense_interface_mtu($realif, $smallermtu);
793
		interfaces_bring_up($realif);
794
		enable_hardware_offloading($member);
795
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
796
	}
797

    
798
	if (isset($bridge['enablestp'])) {
799
		interface_bridge_configure_stp($bridge);
800
	}
801

    
802
	interface_bridge_configure_advanced($bridge);
803

    
804
	interface_bridge_configure_ip6linklocal($bridge);
805

    
806
	if ($flush) {
807
		get_interface_arr(true);
808
	}
809

    
810
	if ($bridge['bridgeif']) {
811
		interfaces_bring_up($bridge['bridgeif']);
812
	} else {
813
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
814
	}
815
}
816

    
817
function interface_bridge_configure_stp($bridge) {
818
	if (isset($bridge['enablestp'])) {
819
		$bridgeif = trim($bridge['bridgeif']);
820
		/* configure spanning tree proto */
821
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
822

    
823
		if (!empty($bridge['stp'])) {
824
			$stpifs = explode(',', $bridge['stp']);
825
			foreach ($stpifs as $stpif) {
826
				$realif = get_real_interface($stpif);
827
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
828
			}
829
		}
830
		if (!empty($bridge['maxage'])) {
831
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
832
		}
833
		if (!empty($bridge['fwdelay'])) {
834
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
835
		}
836
		if (!empty($bridge['hellotime'])) {
837
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
838
		}
839
		if (!empty($bridge['priority'])) {
840
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
841
		}
842
		if (!empty($bridge['holdcnt'])) {
843
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
844
		}
845
		if (!empty($bridge['ifpriority'])) {
846
			$pconfig = explode(",", $bridge['ifpriority']);
847
			$ifpriority = array();
848
			foreach ($pconfig as $cfg) {
849
				$embcfg = explode_assoc(":", $cfg);
850
				foreach ($embcfg as $key => $value) {
851
					$ifpriority[$key] = $value;
852
				}
853
			}
854
			foreach ($ifpriority as $key => $value) {
855
				$realif = get_real_interface($key);
856
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
857
			}
858
		}
859
		if (!empty($bridge['ifpathcost'])) {
860
			$pconfig = explode(",", $bridge['ifpathcost']);
861
			$ifpathcost = array();
862
			foreach ($pconfig as $cfg) {
863
				$embcfg = explode_assoc(":", $cfg);
864
				foreach ($embcfg as $key => $value) {
865
					$ifpathcost[$key] = $value;
866
				}
867
			}
868
			foreach ($ifpathcost as $key => $value) {
869
				$realif = get_real_interface($key);
870
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
871
			}
872
		}
873
	}
874
}
875

    
876
function interface_bridge_configure_advanced($bridge) {
877
	$bridgeif = trim($bridge['bridgeif']);
878

    
879
	if ($bridge['maxaddr'] <> "") {
880
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
881
	}
882
	if ($bridge['timeout'] <> "") {
883
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
884
	}
885
	if (!empty($bridge['span'])) {
886
		$spanifs = explode(",", $bridge['span']);
887
		foreach ($spanifs as $spanif) {
888
			$realif = get_real_interface($spanif);
889
			mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
890
		}
891
	}
892
	if (!empty($bridge['edge'])) {
893
		$edgeifs = explode(',', $bridge['edge']);
894
		foreach ($edgeifs as $edgeif) {
895
			$realif = get_real_interface($edgeif);
896
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
897
		}
898
	}
899
	if (!empty($bridge['autoedge'])) {
900
		$edgeifs = explode(',', $bridge['autoedge']);
901
		foreach ($edgeifs as $edgeif) {
902
			$realif = get_real_interface($edgeif);
903
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
904
		}
905
	}
906
	if (!empty($bridge['ptp'])) {
907
		$ptpifs = explode(',', $bridge['ptp']);
908
		foreach ($ptpifs as $ptpif) {
909
			$realif = get_real_interface($ptpif);
910
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
911
		}
912
	}
913
	if (!empty($bridge['autoptp'])) {
914
		$ptpifs = explode(',', $bridge['autoptp']);
915
		foreach ($ptpifs as $ptpif) {
916
			$realif = get_real_interface($ptpif);
917
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
918
		}
919
	}
920
	if (!empty($bridge['static'])) {
921
		$stickyifs = explode(',', $bridge['static']);
922
		foreach ($stickyifs as $stickyif) {
923
			$realif = get_real_interface($stickyif);
924
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
925
		}
926
	}
927
	if (!empty($bridge['private'])) {
928
		$privateifs = explode(',', $bridge['private']);
929
		foreach ($privateifs as $privateif) {
930
			$realif = get_real_interface($privateif);
931
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
932
		}
933
	}
934
}
935

    
936
function interface_bridge_configure_ip6linklocal($bridge) {
937
	$bridgeif = trim($bridge['bridgeif']);
938

    
939
	$members = explode(',', $bridge['members']);
940
	if (!count($members)) {
941
		return;
942
	}
943

    
944
	$auto_linklocal = isset($bridge['ip6linklocal']);
945
	$bridgeop = $auto_linklocal ? '' : '-';
946
	$memberop = $auto_linklocal ? '-' : '';
947

    
948
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
949
	foreach ($members as $member) {
950
		$realif = get_real_interface($member);
951
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
952
	}
953
}
954

    
955
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
956
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
957
		return;
958
	}
959

    
960
	if ($flagsapplied == false) {
961
		$mtu = get_interface_mtu($bridgeif);
962
		$mtum = get_interface_mtu($interface);
963
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
964
			pfSense_interface_mtu($interface, $mtu);
965
		}
966

    
967
		hardware_offloading_applyflags($interface);
968
		interfaces_bring_up($interface);
969
	}
970

    
971
	pfSense_bridge_add_member($bridgeif, $interface);
972
	$bridged = config_get_path('bridges/bridged');
973
	if (is_array($bridged)) {
974
		foreach ($bridged as $bridge) {
975
			if ($bridgeif == $bridge['bridgeif']) {
976
				interface_bridge_configure_stp($bridge);
977
				interface_bridge_configure_advanced($bridge);
978
			}
979
		}
980
	}
981
}
982

    
983
function interfaces_lagg_configure($realif = "") {
984
	$i = 0;
985
	$laggs = config_get_path('laggs/lagg');
986
	if (is_array($laggs) && count($laggs)) {
987
		if (platform_booting()) {
988
			echo gettext("Configuring LAGG interfaces...");
989
		}
990
		foreach ($laggs as $lagg) {
991
			if (empty($lagg['laggif'])) {
992
				$lagg['laggif'] = "lagg{$i}";
993
			}
994
			if (!empty($realif) && $realif != $lagg['laggif']) {
995
				continue;
996
			}
997
			/* XXX: Maybe we should report any errors?! */
998
			interface_lagg_configure($lagg, false);
999
			$i++;
1000
		}
1001
		/* Invalidate cache */
1002
		get_interface_arr(true);
1003
		if (platform_booting()) {
1004
			echo gettext("done.") . "\n";
1005
		}
1006
	}
1007
}
1008

    
1009
function interface_lagg_configure($lagg, $flush = true) {
1010
	global $config;
1011

    
1012
	if (!is_array($lagg)) {
1013
		return -1;
1014
	}
1015

    
1016
	$members = explode(',', $lagg['members']);
1017
	if (!count($members)) {
1018
		return -1;
1019
	}
1020

    
1021
	if (platform_booting() || !(empty($lagg['laggif']))) {
1022
		pfSense_interface_destroy($lagg['laggif']);
1023
		pfSense_interface_create2($lagg['laggif']);
1024
		$laggif = $lagg['laggif'];
1025
	} else {
1026
		$laggif = pfSense_interface_create2("lagg");
1027
	}
1028

    
1029
	/* Check if MTU was defined for this lagg interface */
1030
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
1031
	if ($lagg_mtu == 0 &&
1032
	    is_array($config['interfaces'])) {
1033
		foreach ($config['interfaces'] as $tmpinterface) {
1034
			if ($tmpinterface['if'] == $lagg['laggif'] &&
1035
			    !empty($tmpinterface['mtu'])) {
1036
				$lagg_mtu = $tmpinterface['mtu'];
1037
				break;
1038
			}
1039
		}
1040
	}
1041

    
1042
	/* Just in case anything is not working well */
1043
	if ($lagg_mtu == 0) {
1044
		$lagg_mtu = 1500;
1045
	}
1046

    
1047
	// put failover master interface on top of list
1048
	if (($lagg['proto'] == 'failover') && isset($lagg['failovermaster']) &&
1049
	    ($lagg['failovermaster'] != 'auto')) {
1050
		unset($members[array_search($lagg['failovermaster'], $members)]);
1051
		$members = array_merge(array($lagg['failovermaster']), $members);
1052
	}
1053

    
1054
	if (($lagg['proto'] == 'lacp') && isset($lagg['lacptimeout']) &&
1055
	    ($lagg['lacptimeout'] != 'slow')) {
1056
		$lacptimeout = 'lacp_fast_timeout';
1057
	} else {
1058
		$lacptimeout = '';
1059
	}
1060

    
1061
	if ((($lagg['proto'] == 'lacp') || ($lagg['proto'] == 'loadbalance')) &&
1062
	    isset($lagg['lagghash']) && !empty($lagg['lagghash'])) {
1063
		$lagghash = 'lagghash ' . escapeshellarg($lagg['lagghash']);
1064
	} else {
1065
		$lagghash = '';
1066
	}
1067

    
1068
	foreach ($members as $member) {
1069
		if (!does_interface_exist($member)) {
1070
			continue;
1071
		}
1072

    
1073
		/* make sure the parent interface is up */
1074
		pfSense_interface_mtu($member, $lagg_mtu);
1075
		interfaces_bring_up($member);
1076
		hardware_offloading_applyflags($member);
1077

    
1078
		// Ensure there are no nulls in these values. It upsets escapeshellarg()
1079
		$laggif = str_replace("\0", "", $laggif);
1080
		$member = str_replace("\0", "", $member);
1081
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
1082
	}
1083

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

    
1086
	if ($flush) {
1087
		get_interface_arr(true);
1088
	}
1089

    
1090
	interfaces_bring_up($laggif);
1091

    
1092
	return $laggif;
1093
}
1094

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

    
1099
	if (!is_array($gre)) {
1100
		return -1;
1101
	}
1102

    
1103
	$realif = convert_friendly_interface_to_real_interface_name($gre['if']);
1104
	if (!interface_is_vlan($realif)) {
1105
		$realif = get_real_interface($gre['if']);
1106
	}
1107
	$realifip = get_interface_ip($gre['if']);
1108
	$realifip6 = get_interface_ipv6($gre['if']);
1109

    
1110
	/* do not run ifconfig without correct $realifip */
1111
	if ((!$realifip && is_ipaddrv4($gre['remote-addr'])) || 
1112
	    (!$realifip6 && is_ipaddrv6($gre['remote-addr']))) {
1113
		return -1;
1114
	}
1115

    
1116
	/* make sure the parent interface is up */
1117
	interfaces_bring_up($realif);
1118

    
1119
	if (platform_booting() || !(empty($gre['greif']))) {
1120
		pfSense_interface_destroy($gre['greif']);
1121
		pfSense_interface_create2($gre['greif']);
1122
		$greif = $gre['greif'];
1123
	} else {
1124
		$greif = pfSense_interface_create2("gre");
1125
	}
1126

    
1127
	$tunnel_type = '';
1128
	if ((!empty($gre['tunnel-local-addr'])) || (!empty($gre['tunnel-remote-addr']))) {
1129
		$tunnel_type = 'v4';
1130
	}
1131
	if ((!empty($gre['tunnel-local-addr6'])) || (!empty($gre['tunnel-remote-addr6']))) {
1132
		$tunnel_type .= 'v6';
1133
	}
1134

    
1135
	/* Do not change the order here for more see gre(4) NOTES section. */
1136
	if (is_ipaddrv6($gre['remote-addr'])) {
1137
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
1138
	} else {
1139
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
1140
	}
1141
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1142
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
1143
	}
1144
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1145
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1146
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr6']) . " " . escapeshellarg($gre['tunnel-remote-addr6']) . " prefixlen 128");
1147
	}
1148

    
1149
	$parentif = get_real_interface($gre['if']);
1150
	if ($parentif) {
1151
		interfaces_bring_up($parentif);
1152
	} else {
1153
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gre_configure()"));
1154
	}
1155

    
1156
	if (isset($gre['link1'])) {
1157
		if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1158
			mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1159
		}
1160
		if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1161
			mwexec("/sbin/route -6 add " . escapeshellarg($gre['tunnel-remote-addr6']) . "/" . escapeshellarg($gre['tunnel-remote-net6']) . " " . escapeshellarg($gre['tunnel-local-addr6']));
1162
		}
1163
	}
1164
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1165
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1166
		unlink_if_exists("{$g['tmp_path']}/{$greif}_router.last");
1167
	}
1168
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1169
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr6']);
1170
		unlink_if_exists("{$g['tmp_path']}/{$greif}_routerv6.last");
1171
	}
1172

    
1173
	if ($flush) {
1174
		get_interface_arr(true);
1175
	}
1176

    
1177
	interfaces_bring_up($greif);
1178

    
1179
	return $greif;
1180
}
1181

    
1182
function interface_is_type($if, $type) {
1183
	switch ($type) {
1184
		case "gre":
1185
			$list = 'gres';
1186
			$entry = 'gre';
1187
			$entif = 'greif';
1188
			break;
1189
		case "gif":
1190
			$list = 'gifs';
1191
			$entry = 'gif';
1192
			$entif = 'gifif';
1193
			break;
1194
		case "lagg":
1195
			$list = 'laggs';
1196
			$entry = 'lagg';
1197
			$entif = 'laggif';
1198
			break;
1199
		default:
1200
			break;
1201
	}
1202

    
1203
	$entries = config_get_path("{$list}/{$entry}");
1204
	if (!is_array($entries)) {
1205
		return (NULL);
1206
	}
1207

    
1208
	foreach ($entries as $ent) {
1209
		if ($ent[$entif] == $if) {
1210
			return ($ent);
1211
		}
1212
	}
1213
	return (NULL);
1214
}
1215

    
1216
function is_greipsec($if) {
1217
	global $config;
1218

    
1219
	if (ipsec_enabled() && is_array($config['gres']) &&
1220
	    is_array($config['gres']['gre']) &&
1221
	    is_array($config['ipsec']['phase2'])) {
1222
		foreach ($config['gres']['gre'] as $gre) {
1223
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
1224
				foreach ($config['ipsec']['phase2'] as $ph2ent) {
1225
					if (($ph1ent['ikeid'] == $ph2ent['ikeid']) && ($ph2ent['mode'] == 'transport') &&
1226
					    !isset($ph1ent['disabled']) && !isset($ph2ent['disabled']) &&
1227
					    ($ph1ent['interface'] == $gre['if']) && ($gre['greif'] == $if) &&
1228
					    ($ph1ent['remote-gateway'] == $gre['remote-addr'])) {
1229
						    return true;
1230
					}
1231
				}
1232
			}
1233
		}
1234
	}
1235
	return false;
1236
}
1237

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

    
1242
	if (!is_array($gif)) {
1243
		return -1;
1244
	}
1245

    
1246
	$realif = convert_friendly_interface_to_real_interface_name($gif['if']);
1247
	if (!interface_is_vlan($realif)) {
1248
		$realif = get_real_interface($gif['if']);
1249
	}
1250
	$ipaddr = get_interface_ip($gif['if']);
1251

    
1252
	if (is_ipaddrv4($gif['remote-addr'])) {
1253
		if (is_ipaddrv4($ipaddr)) {
1254
			$realifip = $ipaddr;
1255
		} else {
1256
			$realifip = get_interface_ip($gif['if']);
1257
		}
1258
		$realifgw = get_interface_gateway($gif['if']);
1259
	} elseif (is_ipaddrv6($gif['remote-addr'])) {
1260
		if (is_ipaddrv6($ipaddr)) {
1261
			$realifip = $ipaddr;
1262
		} else {
1263
			$realifip = get_interface_ipv6($gif['if']);
1264
		}
1265
		$realifgw = get_interface_gateway_v6($gif['if']);
1266
	}
1267

    
1268
	/* do not run ifconfig without correct $realifip */
1269
	if ((!is_ipaddrv4($realifip) && is_ipaddrv4($gif['remote-addr'])) || 
1270
	    (!is_ipaddrv6($realifip) && is_ipaddrv6($gif['remote-addr']))) {
1271
		return -1;
1272
	}
1273

    
1274
	/* make sure the parent interface is up */
1275
	$parentif = get_real_interface($gif['if']);
1276
	if ($parentif) {
1277
		interfaces_bring_up($parentif);
1278
	} else {
1279
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gif_configure()"));
1280
	}
1281

    
1282
	if (platform_booting() || !(empty($gif['gifif']))) {
1283
		pfSense_interface_destroy($gif['gifif']);
1284
		pfSense_interface_create2($gif['gifif']);
1285
		$gifif = $gif['gifif'];
1286
	} else {
1287
		$gifif = pfSense_interface_create2("gif");
1288
	}
1289

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

    
1329
	if (!platform_booting()) {
1330
		$iflist = get_configured_interface_list();
1331
		foreach ($iflist as $ifname) {
1332
			$if = config_get_path("interfaces/{$ifname}/if", "");
1333
			if ($if == $gifif) {
1334
				if (get_interface_gateway($ifname)) {
1335
					system_routing_configure($ifname);
1336
					break;
1337
				}
1338
				if (get_interface_gateway_v6($ifname)) {
1339
					system_routing_configure($ifname);
1340
					break;
1341
				}
1342
			}
1343
		}
1344
	}
1345

    
1346

    
1347
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1348
		file_put_contents("{$g['tmp_path']}/{$gifif}_router",
1349
		    $gif['tunnel-remote-addr']);
1350
		unlink_if_exists("{$g['tmp_path']}/{$gifif}_router.last");
1351
	} elseif (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1352
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6",
1353
		    $gif['tunnel-remote-addr']);
1354
		unlink_if_exists("{$g['tmp_path']}/{$gifif}_routerv6.last");
1355
	}
1356

    
1357
	route_add_or_change($gif['remote-addr'], $realifgw);
1358

    
1359
	if ($flush) {
1360
		get_interface_arr(true);
1361
	}
1362

    
1363
	interfaces_bring_up($gifif);
1364

    
1365
	return $gifif;
1366
}
1367

    
1368
function interfaces_tunnel_configure($checkparent = 0, $realif = "", $type = "") {
1369
	if (!in_array($type, array('gre', 'gif'))) {
1370
		return;
1371
	}
1372

    
1373
	$tuns = config_get_path("{$type}s/{$type}");
1374
	if (!is_array($tuns) || !count($tuns)) {
1375
		return;
1376
	}
1377

    
1378
	foreach ($tuns as $i => $tunnel) {
1379
		if (empty($tunnel["{$type}if"])) {
1380
			$tunnel["{$type}if"] = $type . $i;
1381
		}
1382
		if (!empty($realif) && $realif != $tunnel["{$type}if"]) {
1383
			continue;
1384
		}
1385

    
1386
		$ipaddrv6 = config_get_path("interfaces/{$tunnel}/if/ipaddrv6");
1387
		if ($checkparent == 1) {
1388
			if (substr($tunnel['if'], 0, 4) == '_vip') {
1389
				continue;
1390
			}
1391
			if (substr($tunnel['if'], 0, 5) == '_lloc') {
1392
				continue;
1393
			}
1394

    
1395
			if ($ipaddrv6 == "track6") {
1396
				continue;
1397
			}
1398
		} elseif ($checkparent == 2) {
1399
			if ((substr($tunnel['if'], 0, 4) != '_vip' &&
1400
			    substr($tunnel['if'], 0, 5) != '_lloc') &&
1401
				$ipaddrv6 != "track6") {
1402
				continue;
1403
			}
1404
		}
1405
		if ($type == 'gif') {
1406
			interface_gif_configure($tunnel, "", false);
1407
		} elseif ($type == 'gre') {
1408
			interface_gre_configure($tunnel, "", false);
1409
		}
1410
	}
1411

    
1412
	/* Invalidate cache */
1413
	get_interface_arr(true);
1414
}
1415

    
1416
/* Build a list of IPsec interfaces */
1417
function interface_ipsec_vti_list_p1($ph1ent) {
1418
	$iface_list = array();
1419

    
1420
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array(config_get_path('ipsec/phase2'))) {
1421
		return $iface_list;
1422
	}
1423

    
1424
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1425
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1426
		return $iface_list;
1427
	}
1428

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

    
1455
function is_interface_ipsec_vti_assigned($phase2) {
1456
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1457
	$vti_interface = null;
1458
	$vtisubnet_spec = ipsec_vti($phase1, true);
1459
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1460
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1461
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1462
			foreach ($vtisubnet_spec as $vtisub) {
1463
				/* Is this for this P2? */
1464
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1465
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1466
					$vti_interface = ipsec_get_ifname($phase1, $vtisub['reqid']);
1467
				}
1468
			}
1469
		} else {
1470
			$vti_interface = ipsec_get_ifname($phase1);
1471
		}
1472
	}
1473
	/* Check if this interface is assigned */
1474
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1475
}
1476
function interface_ipsec_vti_configure($ph1ent, $gateways_status = false) {
1477
	global $config, $ipsec_reqid_base;
1478

    
1479
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1480
		return false;
1481
	}
1482

    
1483
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1484
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1485
		return false;
1486
	}
1487

    
1488
	$left_spec = ipsec_get_phase1_src($ph1ent, $gateways_status);
1489

    
1490
	/* Attempt to resolve the remote gateway if needed */
1491
	$right_spec = ipsec_get_phase1_dst($ph1ent);
1492
	if (empty($right_spec)) {
1493
		/* Far end cannot be resolved */
1494
		return false;
1495
	}
1496

    
1497
	$iface_addrs = array();
1498
	$reqids = array();
1499

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

    
1540
	foreach ($iface_addrs as $ipsecif => $addrs) {
1541
		if (!is_array($addrs)) {
1542
			continue;
1543
		}
1544
		// Create IPsec interface
1545
		if (does_interface_exist($ipsecif)) {
1546
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy");
1547
		}
1548
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsec_reqid_base + $reqids[$ipsecif]));
1549

    
1550
		/* Apply the outer tunnel addresses to the interface */
1551
		$inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
1552
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} tunnel " . escapeshellarg($left_spec) . " " . escapeshellarg($right_spec) . " up");
1553

    
1554
		/* Loop through all of the addresses for this interface and apply them as needed */
1555
		foreach ($addrs as $addr) {
1556
			// apply interface addresses
1557
			if (is_v6($addr['left'])) {
1558
				$inet = "inet6";
1559
				$gwtype = "v6";
1560
				$right = '';
1561
			} else {
1562
				$inet = "inet";
1563
				$gwtype = "";
1564
				$right = escapeshellarg($addr['right']);
1565
			}
1566

    
1567
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . $right . $addr['alias']);
1568
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1569
			if (empty($addr['alias'])) {
1570
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1571
				unlink_if_exists("/tmp/{$ipsecif}_router{$gwtype}.last");
1572
			}
1573
		}
1574
		/* Check/set the MTU if the user configured a custom value.
1575
		 * https://redmine.pfsense.org/issues/9111 */
1576
		$currentvtimtu = get_interface_mtu($ipsecif);
1577
		foreach ($config['interfaces'] as $tmpinterface) {
1578
			if ($tmpinterface['if'] == $ipsecif) {
1579
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1580
					$vtimtu = $tmpinterface['mtu'];
1581
				}
1582
			}
1583
		}
1584
		if (is_numericint($vtimtu)) {
1585
			if ($vtimtu != $currentvtimtu) {
1586
				mwexec("/sbin/ifconfig {$ipsecif} mtu {$vtimtu}");
1587
			}
1588
		}
1589
		system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1590
	}
1591
	return true;
1592
}
1593

    
1594
function interfaces_ipsec_vti_configure($gateways_status = false) {
1595
	global $config;
1596
	$bootmsg = false;
1597

    
1598
	/* Fetch gateway status if not passed */
1599
	if (!is_array($gateways_status)) {
1600
		$gateways_status = return_gateways_status(true);
1601
	}
1602
	if (is_array($config['ipsec']) &&
1603
	    is_array($config['ipsec']['phase1']) &&
1604
	    is_array($config['ipsec']['phase2'])) {
1605
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1606
			if ($ph1ent['disabled']) {
1607
				continue;
1608
			}
1609
			if (interface_ipsec_vti_configure($ph1ent, $gateways_status) &&
1610
			    !$bootmsg && platform_booting()) {
1611
				echo gettext("Configuring IPsec VTI interfaces...");
1612
				$bootmsg = true;
1613
			}
1614
		}
1615
	}
1616
	if (platform_booting() && $bootmsg) {
1617
		echo gettext("done.") . "\n";
1618
	}
1619
}
1620

    
1621
function interfaces_configure() {
1622
	global $g;
1623

    
1624
	/* Set up our loopback interface */
1625
	interfaces_loopback_configure();
1626

    
1627
	/* create the unconfigured wireless clones */
1628
	interfaces_create_wireless_clones();
1629

    
1630
	/* set up LAGG virtual interfaces */
1631
	interfaces_lagg_configure();
1632

    
1633
	/* set up VLAN virtual interfaces */
1634
	interfaces_vlan_configure();
1635

    
1636
	interfaces_qinq_configure(false);
1637

    
1638
	$iflist = get_configured_interface_with_descr();
1639
	$delayed_list = array();
1640
	$bridge_list = array();
1641
	$track6_list = array();
1642
	$dhcp6c_list = array();
1643

    
1644
	/* This is needed to speedup interfaces on bootup. */
1645
	$reload = false;
1646
	if (!platform_booting()) {
1647
		$reload = true;
1648
	}
1649

    
1650
	foreach ($iflist as $if => $ifname) {
1651
		$realif = config_get_path("interfaces/{$if}/if","");
1652
		$ipaddrv6 = config_get_path("interfaces/{$if}/ipaddrv6", "");
1653
		if (strstr($realif, "bridge")) {
1654
			$bridge_list[$if] = $ifname;
1655
		} elseif (strstr($realif, "gre")) {
1656
			$delayed_list[$if] = $ifname;
1657
		} elseif (strstr($realif, "gif")) {
1658
			$delayed_list[$if] = $ifname;
1659
		} elseif (strstr($realif, "ovpn")) {
1660
			continue;
1661
		} elseif (strstr($realif, "ipsec")) {
1662
			continue;
1663
		} elseif ($ipaddrv6 == "track6") {
1664
			$track6_list[$if] = $ifname;
1665
		} else {
1666
			/* do not run dhcp6c if track interface does not exists
1667
			 * see https://redmine.pfsense.org/issues/3965
1668
			 * and https://redmine.pfsense.org/issues/11633 */ 
1669
			if ($ipaddrv6 == "dhcp6") {
1670
				$tr6list = link_interface_to_track6($if);
1671
				if (is_array($tr6list) && !empty($tr6list)) {
1672
					$dhcp6c_list[$if] = $ifname;
1673
					continue;
1674
				}
1675
			}
1676
			if (platform_booting()) {
1677
				printf(gettext("Configuring %s interface..."),
1678
				    $ifname);
1679
			}
1680

    
1681
			if ($g['debug']) {
1682
				log_error(sprintf(gettext("Configuring %s"),
1683
				    $ifname));
1684
			}
1685
			interface_configure($if, $reload);
1686
			if (platform_booting()) {
1687
				echo gettext("done.") . "\n";
1688
			}
1689
		}
1690
	}
1691

    
1692
	/*
1693
	 * NOTE: The following function parameter consists of
1694
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1695
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1696
	 */
1697

    
1698
	/* set up GRE virtual interfaces */
1699
	interfaces_tunnel_configure(1,'','gre');
1700

    
1701
	/* set up GIF virtual interfaces */
1702
	interfaces_tunnel_configure(1,'','gif');
1703

    
1704
	/* set up BRIDGE virtual interfaces */
1705
	interfaces_bridge_configure(1);
1706

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

    
1715
		interface_configure($if, $reload);
1716

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

    
1722
	/* bring up vip interfaces */
1723
	interfaces_vips_configure();
1724

    
1725
	/* set up GRE virtual interfaces */
1726
	interfaces_tunnel_configure(2,'','gre');
1727

    
1728
	/* set up GIF virtual interfaces */
1729
	interfaces_tunnel_configure(2,'','gif');
1730

    
1731
	foreach ($delayed_list as $if => $ifname) {
1732
		if (platform_booting()) {
1733
			printf(gettext("Configuring %s interface..."), $ifname);
1734
		}
1735
		if ($g['debug']) {
1736
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1737
		}
1738

    
1739
		interface_configure($if, $reload);
1740

    
1741
		if (platform_booting()) {
1742
			echo gettext("done.") . "\n";
1743
		}
1744
	}
1745

    
1746
	/* set up BRIDGE virtual interfaces */
1747
	interfaces_bridge_configure(2);
1748

    
1749
	foreach ($bridge_list as $if => $ifname) {
1750
		if (platform_booting()) {
1751
			printf(gettext("Configuring %s interface..."), $ifname);
1752
		}
1753
		if ($g['debug']) {
1754
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1755
		}
1756

    
1757
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1758
		// redmine #3997
1759
		interface_reconfigure($if, $reload);
1760
		interfaces_vips_configure($if);
1761

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

    
1767
	foreach ($dhcp6c_list as $if => $ifname) {
1768
		if (platform_booting()) {
1769
			printf(gettext("Configuring %s interface..."), $ifname);
1770
		}
1771
		if ($g['debug']) {
1772
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1773
		}
1774

    
1775
		interface_configure($if, $reload);
1776

    
1777
		if (platform_booting()) {
1778
			echo gettext("done.") . "\n";
1779
		}
1780
	}
1781

    
1782
	/* set up IPsec VTI interfaces */
1783
	interfaces_ipsec_vti_configure();
1784

    
1785
	/* configure interface groups */
1786
	interfaces_group_setup();
1787

    
1788
	if (!platform_booting()) {
1789
		/* reconfigure static routes (kernel may have deleted them) */
1790
		system_routing_configure();
1791

    
1792
		/* reload IPsec tunnels */
1793
		ipsec_configure();
1794

    
1795
		/* restart dns servers (defering dhcpd reload) */
1796
		if (config_get_path('dnsmasq/enable')) {
1797
			services_dnsmasq_configure(false);
1798
		}
1799
		if (config_get_path('unbound/enable')) {
1800
			services_unbound_configure(false);
1801
		}
1802

    
1803
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1804
		services_dhcpd_configure();
1805
	}
1806

    
1807
	return 0;
1808
}
1809

    
1810
function interface_reconfigure($interface = "wan", $reloadall = false) {
1811
	interface_bring_down($interface);
1812
	interface_configure($interface, $reloadall);
1813
}
1814

    
1815
function interface_vip_bring_down($vip) {
1816
	global $g;
1817

    
1818
	$vipif = get_real_interface($vip['interface']);
1819
	switch ($vip['mode']) {
1820
		case "proxyarp":
1821
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1822
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1823
			}
1824
			break;
1825
		case "ipalias":
1826
			if (does_interface_exist($vipif)) {
1827
				if (is_ipaddrv6($vip['subnet'])) {
1828
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1829
				} else {
1830
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1831
				}
1832
			}
1833
			break;
1834
		case "carp":
1835
			/* XXX: Is enough to delete ip address? */
1836
			if (does_interface_exist($vipif)) {
1837
				if (is_ipaddrv6($vip['subnet'])) {
1838
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1839
				} else {
1840
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1841
				}
1842
			}
1843
			break;
1844
	}
1845
}
1846

    
1847
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1848
	global $config, $g;
1849

    
1850
	$iface = config_get_path("interfaces/{$interface}");
1851
	if (!$iface) {
1852
		return;
1853
	}
1854

    
1855
	if ($g['debug']) {
1856
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1857
	}
1858

    
1859
	/*
1860
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1861
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1862
	 * Keep this in mind while doing changes here!
1863
	 */
1864
	if ($ifacecfg === false) {
1865
		$ifcfg = $iface;
1866
		$ppps = $config['ppps']['ppp'];
1867
		$realif = get_real_interface($interface);
1868
		$realifv6 = get_real_interface($interface, "inet6", true);
1869
	} elseif (!is_array($ifacecfg)) {
1870
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1871
		$ifcfg = $iface;
1872
		$ppps = $config['ppps']['ppp'];
1873
		$realif = get_real_interface($interface);
1874
		$realifv6 = get_real_interface($interface, "inet6", true);
1875
	} else {
1876
		$ifcfg = $ifacecfg['ifcfg'];
1877
		$ppps = $ifacecfg['ppps'];
1878
		if (isset($ifacecfg['ifcfg']['realif'])) {
1879
			$realif = $ifacecfg['ifcfg']['realif'];
1880
			/* XXX: Any better way? */
1881
			$realifv6 = $realif;
1882
		} else {
1883
			$realif = get_real_interface($interface);
1884
			$realifv6 = get_real_interface($interface, "inet6", true);
1885
		}
1886
	}
1887

    
1888
	/* check all gateways, including dynamic,
1889
	 * see https://redmine.pfsense.org/issues/12920 */
1890
	foreach (return_gateways_array(true) as $gw) {
1891
		if ($gw['friendlyiface'] == $interface) {
1892
			$restart_gateways_monitor = true;
1893
			break;
1894
		}
1895
	}
1896

    
1897
	switch ($ifcfg['ipaddr']) {
1898
		case "ppp":
1899
		case "pppoe":
1900
		case "pptp":
1901
		case "l2tp":
1902
			if (is_array($ppps) && count($ppps)) {
1903
				foreach ($ppps as  $ppp) {
1904
					if ($realif == $ppp['if']) {
1905
						if (isset($ppp['ondemand']) && !$destroy) {
1906
							send_event("interface reconfigure {$interface}");
1907
							break;
1908
						}
1909
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1910
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1911
							sleep(2);
1912
						}
1913
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1914
						break;
1915
					}
1916
				}
1917
			}
1918
			break;
1919
		case "dhcp":
1920
			kill_dhclient_process($realif);
1921
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1922
			if (does_interface_exist("$realif")) {
1923
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1924
				interface_vip_cleanup($interface, "inet4");
1925
				if ($destroy == true) {
1926
					pfSense_interface_flags($realif, -IFF_UP);
1927
				}
1928
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1929
			}
1930
			break;
1931
		default:
1932
			if (does_interface_exist("$realif")) {
1933
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1934
				interface_vip_cleanup($interface, "inet4");
1935
				if ($destroy == true) {
1936
					pfSense_interface_flags($realif, -IFF_UP);
1937
				}
1938
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1939
			}
1940
			break;
1941
	}
1942

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

    
2002
	if (!empty($track6) && is_array($track6)) {
2003
		if (!function_exists('services_dhcpd_configure')) {
2004
			require_once('services.inc');
2005
		}
2006
		/* Bring down radvd and dhcp6 on these interfaces */
2007
		services_dhcpd_configure('inet6', $track6);
2008
	}
2009

    
2010
	/* remove interface up file if it exists */
2011
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
2012
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
2013
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
2014
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
2015
		rename("{$g['tmp_path']}/{$realif}_router", "{$g['tmp_path']}/{$realif}_router.last");
2016
	}
2017
	if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
2018
		rename("{$g['tmp_path']}/{$realif}_routerv6", "{$g['tmp_path']}/{$realif}_routerv6.last");
2019
	}
2020
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
2021
	unlink_if_exists("{$g['varetc_path']}/nameserver_v6{$interface}");
2022
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
2023
	unlink_if_exists("{$g['varetc_path']}/searchdomain_v6{$interface}");
2024
	unlink_if_exists("{$g['tmp_path']}/{$interface}_upstart4");
2025
	unlink_if_exists("{$g['tmp_path']}/{$interface}_upstart6");
2026

    
2027
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
2028
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
2029
	if (is_array($ifcfg['wireless'])) {
2030
		kill_hostapd($realif);
2031
		mwexec(kill_wpasupplicant($realif));
2032
		unlink_if_exists("{$g['varetc_path']}/wpa_supplicant_{$realif}.*");
2033
		unlink_if_exists("{$g['varetc_path']}/hostapd_{$realif}.conf");
2034
	}
2035

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

    
2040
			/* Invalidate cache */
2041
			get_interface_arr(true);
2042
		}
2043
	}
2044

    
2045
	/* If interface has a gateway, we need to bounce dpinger to keep dpinger happy */
2046
	if ($restart_gateways_monitor) {
2047
		setup_gateways_monitor();
2048
	}
2049

    
2050
	return;
2051
}
2052

    
2053
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
2054
	global $config;
2055
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
2056
		unset($config["virtualip_carp_maintenancemode"]);
2057
		write_config("Leave CARP maintenance mode");
2058
	} elseif (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
2059
		$config["virtualip_carp_maintenancemode"] = true;
2060
		write_config(gettext("Enter CARP maintenance mode"));
2061
	}
2062
	init_config_arr(array('virtualip', 'vip'));
2063
	$viparr = &$config['virtualip']['vip'];
2064

    
2065
	if (is_array($viparr)) {
2066
		foreach ($viparr as $vip) {
2067
			if ($vip['mode'] == "carp") {
2068
				interface_carp_configure($vip, true);
2069
			}
2070
		}
2071
	}
2072
}
2073

    
2074
function interface_wait_tentative($interface, $timeout = 10) {
2075
	if (!does_interface_exist($interface)) {
2076
		return false;
2077
	}
2078

    
2079
	$time = 0;
2080
	while ($time <= $timeout) {
2081
		$if = get_interface_addresses($interface);
2082
		if (!isset($if['tentative'])) {
2083
			return true;
2084
		}
2085
		sleep(1);
2086
		$time++;
2087
	}
2088

    
2089
	return false;
2090
}
2091

    
2092
function interface_isppp_type($interface) {
2093
	$iface = config_get_path("interfaces/{$interface}");
2094
	if (!is_array($iface)) {
2095
		return false;
2096
	}
2097

    
2098
	switch ($iface['ipaddr']) {
2099
		case 'pptp':
2100
		case 'l2tp':
2101
		case 'pppoe':
2102
		case 'ppp':
2103
			return true;
2104
			break;
2105
		default:
2106
			return false;
2107
			break;
2108
	}
2109
}
2110

    
2111
function interfaces_ptpid_used($ptpid) {
2112
	$ppps = config_get_path('ppps/ppp');
2113
	if (is_array($ppps)) {
2114
		foreach ($ppps as $settings) {
2115
			if ($ptpid == $settings['ptpid']) {
2116
				return true;
2117
			}
2118
		}
2119
	}
2120

    
2121
	return false;
2122
}
2123

    
2124
function interfaces_ptpid_next() {
2125
	$ptpid = 0;
2126
	while (interfaces_ptpid_used($ptpid)) {
2127
		$ptpid++;
2128
	}
2129

    
2130
	return $ptpid;
2131
}
2132

    
2133
function getMPDCRONSettings($pppif) {
2134
	global $g;
2135

    
2136
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2137
	foreach (config_get_path('cron/item', []) as $i => $item) {
2138
		if (stripos($item['command'], $cron_cmd_file) !== false) {
2139
			return array("ID" => $i, "ITEM" => $item);
2140
		}
2141
	}
2142

    
2143
	return NULL;
2144
}
2145

    
2146
function handle_pppoe_reset($post_array) {
2147
	global $config, $g;
2148

    
2149
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2150
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2151

    
2152
	if (!is_array(config_get_path('cron/item'))) {
2153
		if (config_set_path('cron/item', array()) === null)
2154
			log_error(gettext('Cron section missing from config root.'));
2155
			return;
2156
	}
2157

    
2158
	$itemhash = getMPDCRONSettings($pppif);
2159

    
2160
	// reset cron items if necessary and return
2161
	if (empty($post_array['pppoe-reset-type'])) {
2162
		if (isset($itemhash)) {
2163
			unset($config['cron']['item'][$itemhash['ID']]);
2164
		}
2165
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2166
		return;
2167
	}
2168

    
2169
	if (empty($itemhash)) {
2170
		$itemhash = array();
2171
	}
2172
	$item = array();
2173
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
2174
		$item['minute'] = $post_array['pppoe_resetminute'] ? $post_array['pppoe_resetminute'] : "*";
2175
		$item['hour'] = $post_array['pppoe_resethour'] ? $post_array['pppoe_resethour'] : "*";
2176
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
2177
			$date = explode("/", $post_array['pppoe_resetdate']);
2178
			$item['mday'] = $date[1];
2179
			$item['month'] = $date[0];
2180
		} else {
2181
			$item['mday'] = "*";
2182
			$item['month'] = "*";
2183
		}
2184
		$item['wday'] = "*";
2185
		$item['who'] = "root";
2186
		$item['command'] = $cron_cmd_file;
2187
	} elseif (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
2188
		switch ($post_array['pppoe_pr_preset_val']) {
2189
			case "monthly":
2190
				$item['minute'] = "0";
2191
				$item['hour'] = "0";
2192
				$item['mday'] = "1";
2193
				$item['month'] = "*";
2194
				$item['wday'] = "*";
2195
				break;
2196
			case "weekly":
2197
				$item['minute'] = "0";
2198
				$item['hour'] = "0";
2199
				$item['mday'] = "*";
2200
				$item['month'] = "*";
2201
				$item['wday'] = "0";
2202
				break;
2203
			case "daily":
2204
				$item['minute'] = "0";
2205
				$item['hour'] = "0";
2206
				$item['mday'] = "*";
2207
				$item['month'] = "*";
2208
				$item['wday'] = "*";
2209
				break;
2210
			case "hourly":
2211
				$item['minute'] = "0";
2212
				$item['hour'] = "*";
2213
				$item['mday'] = "*";
2214
				$item['month'] = "*";
2215
				$item['wday'] = "*";
2216
				break;
2217
		} // end switch
2218
		$item['who'] = "root";
2219
		$item['command'] = $cron_cmd_file;
2220
	}
2221
	if (empty($item)) {
2222
		return;
2223
	}
2224
	if (isset($itemhash['ID'])) {
2225
		$config['cron']['item'][$itemhash['ID']] = $item;
2226
	} else {
2227
		$config['cron']['item'][] = $item;
2228
	}
2229
}
2230

    
2231
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2232
	$ppp_list = array();
2233
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
2234
		$ports = explode(",", $ppp['ports']);
2235
		foreach($ports as $port) {
2236
			foreach($triggerinterfaces as $vip) {
2237
				if ($port == "_vip{$vip['uniqid']}") {
2238
					$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2239
					$ppp_list[$if] = 1;
2240
				}
2241
			}
2242
		}
2243
	}
2244
	foreach(array_keys($ppp_list) as $pppif) {
2245
		interface_ppps_configure($pppif);
2246
	}
2247
}
2248

    
2249
/*
2250
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2251
 * It writes the mpd config file to /var/etc every time the link is opened.
2252
 */
2253
function interface_ppps_configure($interface) {
2254
	global $config, $g;
2255

    
2256
	$iface = config_get_path("interfaces/{$interface}");
2257
	/* Return for unassigned interfaces. This is a minimum requirement. */
2258
	if (empty($iface)) {
2259
		return 0;
2260
	}
2261
	$ifcfg = $iface;
2262
	if (!isset($ifcfg['enable'])) {
2263
		return 0;
2264
	}
2265

    
2266
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2267
	if (!is_dir("/var/spool/lock")) {
2268
		mkdir("/var/spool/lock", 0777, true);
2269
	}
2270
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2271
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2272
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2273
	}
2274

    
2275
	$pppid = "";
2276
	$ppp = array();
2277
	$ppps = config_get_path('ppps/ppp');
2278
	if (is_array($ppps) && count($ppps)) {
2279
		foreach ($ppps as $pppid => $ppp) {
2280
			if ($ifcfg['if'] == $ppp['if']) {
2281
				break;
2282
			}
2283
		}
2284
	}
2285
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2286
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2287
		return 0;
2288
	}
2289
	$pppif = $ifcfg['if'];
2290
	if ($ppp['type'] == "ppp") {
2291
		$type = "modem";
2292
	} else {
2293
		$type = $ppp['type'];
2294
	}
2295

    
2296
	$confports = explode(',', $ppp['ports']);
2297
	if ($type == "modem") {
2298
		$ports = $confports;
2299
	} else {
2300
		$ports = array();
2301
		foreach ($confports as $pid => $port) {
2302
			if (strstr($port, "_vip")) {
2303
				if (get_carp_interface_status($port) != "MASTER") {
2304
					continue;
2305
				}
2306
			}
2307
			$ports[$pid] = get_real_interface($port);
2308
			if (empty($ports[$pid])) {
2309
				return 0;
2310
			}
2311
		}
2312
	}
2313
	$localips = explode(',', $ppp['localip']);
2314
	$gateways = explode(',', $ppp['gateway']);
2315
	$subnets = explode(',', $ppp['subnet']);
2316

    
2317
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2318
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2319
	 */
2320
	foreach ($ports as $pid => $port) {
2321
		switch ($ppp['type']) {
2322
			case "pppoe":
2323
				/* Bring the parent interface up */
2324
				interfaces_bring_up($port);
2325
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2326
				$ngif = str_replace(".", "_", $port);
2327
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2328
				break;
2329
			case "pptp":
2330
			case "l2tp":
2331
				/* configure interface */
2332
				if (is_ipaddr($localips[$pid])) {
2333
					// Manually configure interface IP/subnet
2334
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2335
					interfaces_bring_up($port);
2336
				} elseif (empty($localips[$pid])) {
2337
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2338
				}
2339

    
2340
				if (!is_ipaddr($localips[$pid])) {
2341
					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));
2342
					$localips[$pid] = "0.0.0.0";
2343
				}
2344
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2345
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2346
				}
2347
				if (!is_ipaddr($gateways[$pid])) {
2348
					log_error(sprintf(gettext('Could not get a PPTP/L2TP Remote IP address from %1$s for %2$s in interfaces_ppps_configure.'), $localips[$pid], $ppp['gateway']));
2349
					return 0;
2350
				}
2351
				break;
2352
			case "ppp":
2353
				if (!file_exists("{$port}")) {
2354
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2355
					return 0;
2356
				}
2357
				break;
2358
			default:
2359
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2360
				break;
2361
		}
2362
	}
2363

    
2364
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2365
	    (is_array($ports) && count($ports) > 1)) {
2366
		$multilink = "enable";
2367
	} else {
2368
		$multilink = "disable";
2369
	}
2370

    
2371
	if ($type == "modem") {
2372
		if (is_ipaddr($ppp['localip'])) {
2373
			$localip = $ppp['localip'];
2374
		} else {
2375
			$localip = '0.0.0.0';
2376
		}
2377

    
2378
		if (is_ipaddr($ppp['gateway'])) {
2379
			$gateway = $ppp['gateway'];
2380
		} else {
2381
			$gateway = "10.64.64.{$pppid}";
2382
		}
2383
		$ranges = "{$localip}/0 {$gateway}/0";
2384

    
2385
		if (empty($ppp['apnum'])) {
2386
			$ppp['apnum'] = 1;
2387
		}
2388
	} else {
2389
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2390
	}
2391

    
2392
	if (isset($ppp['ondemand'])) {
2393
		$ondemand = "enable";
2394
	} else {
2395
		$ondemand = "disable";
2396
	}
2397
	if (!isset($ppp['idletimeout'])) {
2398
		$ppp['idletimeout'] = 0;
2399
	}
2400

    
2401
	if (empty($ppp['username']) && $type == "modem") {
2402
		$ppp['username'] = "user";
2403
		$ppp['password'] = "none";
2404
	}
2405
	if (empty($ppp['password']) && $type == "modem") {
2406
		$passwd = "none";
2407
	} else {
2408
		$passwd = base64_decode($ppp['password']);
2409
	}
2410

    
2411
	$bandwidths = explode(',', $ppp['bandwidth']);
2412
	$defaultmtu = "1492";
2413
	if (!empty($ifcfg['mtu'])) {
2414
		$defaultmtu = intval($ifcfg['mtu']);
2415
	}
2416
	if (isset($ppp['mtu'])) {
2417
		$mtus = explode(',', $ppp['mtu']);
2418
	}
2419
	if (isset($ppp['mru'])) {
2420
		$mrus = explode(',', $ppp['mru']);
2421
	}
2422
	if (isset($ppp['mrru'])) {
2423
		$mrrus = explode(',', $ppp['mrru']);
2424
	}
2425
	if (!empty($ifcfg['ipaddrv6'])) {
2426
		$ipv6cp = "set bundle enable ipv6cp";
2427
	}
2428

    
2429
	// Construct the mpd.conf file
2430
	$mpdconf = <<<EOD
2431
startup:
2432
	# configure the console
2433
	set console close
2434
	# configure the web server
2435
	set web close
2436

    
2437
default:
2438
{$ppp['type']}client:
2439
	create bundle static {$interface}
2440
	set bundle period 6
2441
	set bundle lowat 0
2442
	set bundle hiwat 0
2443
	set bundle min-con 3
2444
	set bundle min-dis 6
2445
	set bundle enable bw-manage
2446
	{$ipv6cp}
2447
	set iface name {$pppif}
2448

    
2449
EOD;
2450

    
2451
	if (isset($ifcfg['descr'])) {
2452
		$mpdconf .= <<<EOD
2453
	set iface description "{$ifcfg['descr']}"
2454

    
2455
EOD;
2456
	}
2457
	$setdefaultgw = false;
2458
	$defgw4 = lookup_gateway_or_group_by_name(config_get_path('gateways/defaultgw4'));
2459
//	$defgw6 = lookup_gateway_or_group_by_name(config_get_path('gateways/defaultgw6'));
2460
	if ($defgw4['interface'] == $interface) {
2461
		$setdefaultgw = true;
2462
	}
2463

    
2464
/* Omit this, we maintain the default route by other means, and it causes problems with
2465
 * default gateway switching. See redmine #1837 for original issue
2466
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2467
 * edge case. redmine #6495 open to address.
2468
 */
2469
	if ($setdefaultgw == true) {
2470
		$mpdconf .= <<<EOD
2471
	set iface route default
2472

    
2473
EOD;
2474
	}
2475

    
2476
	$mpdconf .= <<<EOD
2477
	set iface {$ondemand} on-demand
2478
	set iface idle {$ppp['idletimeout']}
2479

    
2480
EOD;
2481

    
2482
	if (isset($ppp['ondemand'])) {
2483
		$mpdconf .= <<<EOD
2484
	set iface addrs 10.10.1.1 10.10.1.2
2485

    
2486
EOD;
2487
	}
2488

    
2489
	if (isset($ppp['mtu-override']) &&
2490
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2491
		/* Find the smaller MTU set on ports */
2492
		$mtu = $defaultmtu;
2493
		foreach ($ports as $pid => $port) {
2494
			if (empty($mtus[$pid])) {
2495
				$mtus[$pid] = $defaultmtu;
2496
			}
2497
			if ($type == "pppoe") {
2498
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2499
					$mtus[$pid] = get_interface_mtu($port) - 8;
2500
				}
2501
			}
2502
			if ($mtu > $mtus[$pid]) {
2503
				$mtu = $mtus[$pid];
2504
			}
2505
		}
2506
		$mpdconf .= <<<EOD
2507
	set iface mtu {$mtu} override
2508

    
2509
EOD;
2510
	}
2511

    
2512
	if (isset($ppp['tcpmssfix'])) {
2513
		$tcpmss = "disable";
2514
	} else {
2515
		$tcpmss = "enable";
2516
	}
2517
	$mpdconf .= <<<EOD
2518
	set iface {$tcpmss} tcpmssfix
2519

    
2520
EOD;
2521

    
2522
	$mpdconf .= <<<EOD
2523
	set iface up-script /usr/local/sbin/ppp-linkup
2524
	set iface down-script /usr/local/sbin/ppp-linkdown
2525
	set ipcp ranges {$ranges}
2526

    
2527
EOD;
2528
	if (isset($ppp['vjcomp'])) {
2529
		$mpdconf .= <<<EOD
2530
	set ipcp no vjcomp
2531

    
2532
EOD;
2533
	}
2534

    
2535
	if (config_get_path('system/dnsallowoverride')) {
2536
		$mpdconf .= <<<EOD
2537
	set ipcp enable req-pri-dns
2538
	set ipcp enable req-sec-dns
2539

    
2540
EOD;
2541
	}
2542

    
2543
	if (!isset($ppp['verbose_log'])) {
2544
		$mpdconf .= <<<EOD
2545
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2546

    
2547
EOD;
2548
	}
2549

    
2550
	foreach ($ports as $pid => $port) {
2551
		$port = get_real_interface($port);
2552
		$mpdconf .= <<<EOD
2553

    
2554
	create link static {$interface}_link{$pid} {$type}
2555
	set link action bundle {$interface}
2556
	set link {$multilink} multilink
2557
	set link keep-alive 10 60
2558
	set link max-redial 0
2559

    
2560
EOD;
2561
		if (isset($ppp['shortseq'])) {
2562
			$mpdconf .= <<<EOD
2563
	set link no shortseq
2564

    
2565
EOD;
2566
		}
2567

    
2568
		if (isset($ppp['acfcomp'])) {
2569
			$mpdconf .= <<<EOD
2570
	set link no acfcomp
2571

    
2572
EOD;
2573
		}
2574

    
2575
		if (isset($ppp['protocomp'])) {
2576
			$mpdconf .= <<<EOD
2577
	set link no protocomp
2578

    
2579
EOD;
2580
		}
2581

    
2582
		$mpdconf .= <<<EOD
2583
	set link disable chap pap
2584
	set link accept chap pap eap
2585
	set link disable incoming
2586

    
2587
EOD;
2588

    
2589

    
2590
		if (!empty($bandwidths[$pid])) {
2591
			$mpdconf .= <<<EOD
2592
	set link bandwidth {$bandwidths[$pid]}
2593

    
2594
EOD;
2595
		}
2596

    
2597
		if (empty($mtus[$pid])) {
2598
			$mtus[$pid] = $defaultmtu;
2599
		}
2600
		if ($type == "pppoe") {
2601
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2602
				$mtus[$pid] = get_interface_mtu($port) - 8;
2603
			}
2604
		}
2605
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2606
		    !isset($ppp['mtu-override']) &&
2607
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2608
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2609
			$mpdconf .= <<<EOD
2610
	set link mtu {$mtus[$pid]}
2611

    
2612
EOD;
2613
		}
2614

    
2615
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2616
		    !isset($ppp['mtu-override']) &&
2617
		    !empty($mrus[$pid])) {
2618
			$mpdconf .= <<<EOD
2619
	set link mru {$mrus[$pid]}
2620

    
2621
EOD;
2622
		}
2623

    
2624
		if (!empty($mrrus[$pid])) {
2625
			$mpdconf .= <<<EOD
2626
	set link mrru {$mrrus[$pid]}
2627

    
2628
EOD;
2629
		}
2630

    
2631
		$mpdconf .= <<<EOD
2632
	set auth authname "{$ppp['username']}"
2633
	set auth password {$passwd}
2634

    
2635
EOD;
2636
		if ($type == "modem") {
2637
			$mpdconf .= <<<EOD
2638
	set modem device {$ppp['ports']}
2639
	set modem script DialPeer
2640
	set modem idle-script Ringback
2641
	set modem watch -cd
2642
	set modem var \$DialPrefix "DT"
2643
	set modem var \$Telephone "{$ppp['phone']}"
2644

    
2645
EOD;
2646
		}
2647
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2648
			$mpdconf .= <<<EOD
2649
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2650

    
2651
EOD;
2652
		}
2653
		if (isset($ppp['initstr']) && $type == "modem") {
2654
			$initstr = base64_decode($ppp['initstr']);
2655
			$mpdconf .= <<<EOD
2656
	set modem var \$InitString "{$initstr}"
2657

    
2658
EOD;
2659
		}
2660
		if (isset($ppp['simpin']) && $type == "modem") {
2661
			if ($ppp['pin-wait'] == "") {
2662
				$ppp['pin-wait'] = 0;
2663
			}
2664
			$mpdconf .= <<<EOD
2665
	set modem var \$SimPin "{$ppp['simpin']}"
2666
	set modem var \$PinWait "{$ppp['pin-wait']}"
2667

    
2668
EOD;
2669
		}
2670
		if (isset($ppp['apn']) && $type == "modem") {
2671
			$mpdconf .= <<<EOD
2672
	set modem var \$APN "{$ppp['apn']}"
2673
	set modem var \$APNum "{$ppp['apnum']}"
2674

    
2675
EOD;
2676
		}
2677
		if ($type == "pppoe") {
2678
			$hostuniq = '';
2679
			if (!empty($ppp['hostuniq'])) {
2680
				if (preg_match('/^0x[a-fA-F0-9]+$/', $ppp['hostuniq'])) {
2681
					$hostuniq = strtolower($ppp['hostuniq']) .'|';
2682
				} elseif (preg_match('/^[a-zA-Z0-9]+$/i', $ppp['hostuniq'])) {
2683
					$hostuniq = '0x' . bin2hex($ppp['hostuniq']) . '|';
2684
				}
2685
			}
2686
			// Send a null service name if none is set.
2687
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2688
			$mpdconf .= <<<EOD
2689
	set pppoe service "{$hostuniq}{$provider}"
2690

    
2691
EOD;
2692
		}
2693
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2694
			$mpdconf .= <<<EOD
2695
	set pppoe max-payload {$mtus[$pid]}
2696

    
2697
EOD;
2698
		}
2699
		if ($type == "pppoe") {
2700
			$mpdconf .= <<<EOD
2701
	set pppoe iface {$port}
2702

    
2703
EOD;
2704
		}
2705

    
2706
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2707
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2708
			$mpdconf .= <<<EOD
2709
	set l2tp secret "{$secret}"
2710

    
2711
EOD;
2712
		}
2713

    
2714
		if (($type == "pptp") || ($type == "l2tp")) {
2715
			$mpdconf .= <<<EOD
2716
	set {$type} self {$localips[$pid]}
2717
	set {$type} peer {$gateways[$pid]}
2718

    
2719
EOD;
2720
		}
2721

    
2722
		$mpdconf .= "\topen\n";
2723
	} //end foreach ($port)
2724

    
2725

    
2726
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2727
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2728
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2729
	} else {
2730
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2731
		if (!$fd) {
2732
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2733
			return 0;
2734
		}
2735
		// Write out mpd_ppp.conf
2736
		fwrite($fd, $mpdconf);
2737
		fclose($fd);
2738
		unset($mpdconf);
2739
	}
2740

    
2741
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2742
	if (isset($ppp['uptime'])) {
2743
		if (!file_exists("/conf/{$pppif}.log")) {
2744
			file_put_contents("/conf/{$pppif}.log", '');
2745
		}
2746
	} else {
2747
		if (file_exists("/conf/{$pppif}.log")) {
2748
			@unlink("/conf/{$pppif}.log");
2749
		}
2750
	}
2751

    
2752
	/* clean up old lock files */
2753
	foreach ($ports as $port) {
2754
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2755
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2756
		}
2757
	}
2758

    
2759
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2760
	/* random IPv6 interface identifier during boot. More details at */
2761
	/* https://forum.netgate.com/post/592474 */
2762
	if (platform_booting() && is_array($config['interfaces'])) {
2763
		$count = 0;
2764
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2765
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2766
				$tempaddr[$count]['if'] = $tempiface['if'];
2767
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2768
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2769
				$count++;
2770
			}
2771
			// Maximum /31 is is x.y.z.254/31
2772
			if ($count > 122) {
2773
				break;
2774
			}
2775
		}
2776
		unset($count);
2777
	}
2778

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

    
2784
	// Check for PPPoE periodic reset request
2785
	if ($type == "pppoe") {
2786
		if (!empty($ppp['pppoe-reset-type'])) {
2787
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2788
		} else {
2789
			interface_setup_pppoe_reset_file($ppp['if']);
2790
		}
2791
	}
2792
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2793
	$i = 0;
2794
	while ($i < 10) {
2795
		if (does_interface_exist($ppp['if'], true)) {
2796
			break;
2797
		}
2798
		sleep(3);
2799
		$i++;
2800
	}
2801

    
2802
	/* Remove all temporary bogon IPv4 addresses */
2803
	if (is_array($tempaddr)) {
2804
		foreach ($tempaddr as $tempiface) {
2805
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2806
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2807
			}
2808
		}
2809
		unset ($tempaddr);
2810
	}
2811

    
2812
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2813
	/* We should be able to launch the right version for each modem */
2814
	/* We can also guess the mondev from the manufacturer */
2815
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2816
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2817
	foreach ($ports as $port) {
2818
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2819
			$mondev = substr(basename($port), 0, -1);
2820
			$devlist = glob("/dev/{$mondev}?");
2821
			$mondev = basename(end($devlist));
2822
		}
2823
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2824
			$mondev = substr(basename($port), 0, -1) . "1";
2825
		}
2826
		if ($mondev != '') {
2827
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2828
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2829
		}
2830
	}
2831

    
2832
	return 1;
2833
}
2834

    
2835
function interfaces_sync_setup() {
2836
	global $config;
2837

    
2838
	if (config_get_path('system/developerspew')) {
2839
		$mt = microtime();
2840
		echo "interfaces_sync_setup() being called $mt\n";
2841
	}
2842

    
2843
	if (platform_booting()) {
2844
		echo gettext("Configuring CARP settings...");
2845
		mute_kernel_msgs();
2846
	}
2847

    
2848
	/* suck in configuration items */
2849
	if ($config['hasync']) {
2850
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2851
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2852
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2853
	}
2854

    
2855
	set_sysctl(array(
2856
		"net.inet.carp.preempt" => "1",
2857
		"net.inet.carp.log" => "1")
2858
	);
2859

    
2860
	if (!empty($pfsyncinterface)) {
2861
		$carp_sync_int = get_real_interface($pfsyncinterface);
2862
	}
2863

    
2864
	/* setup pfsync interface */
2865
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2866
		if (is_ipaddr($pfsyncpeerip)) {
2867
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2868
		} else {
2869
			$syncpeer = "-syncpeer";
2870
		}
2871

    
2872
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} " .
2873
		    "{$syncpeer} up");
2874
		mwexec("/sbin/ifconfig pfsync0 -defer");
2875

    
2876
		/*
2877
		 * XXX: Handle an issue with pfsync(4) and carp(4). In a
2878
		 * cluster carp will come up before pfsync(4) has updated and
2879
		 * so will cause issues for existing sessions.
2880
		 */
2881
		log_error(gettext("waiting for pfsync..."));
2882

    
2883
		$i = 0;
2884
		do {
2885
			sleep(1);
2886
			exec('/sbin/ifconfig pfsync0 | ' .
2887
				 '/usr/bin/grep -q "syncok: 0" 2>/dev/null', $output,
2888
				 $rc);
2889
			$i++;
2890
		} while ($rc != 0 && $i <= 30);
2891

    
2892
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2893
		log_error(gettext("Configuring CARP settings finalize..."));
2894
	} else {
2895
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down");
2896
	}
2897

    
2898
	$carplist = get_configured_vip_list('all', VIP_CARP);
2899
	if (is_array($carplist) && count($carplist) > 0) {
2900
		set_single_sysctl("net.inet.carp.allow", "1");
2901
	} else {
2902
		set_single_sysctl("net.inet.carp.allow", "0");
2903
	}
2904

    
2905
	if (platform_booting()) {
2906
		unmute_kernel_msgs();
2907
		echo gettext("done.") . "\n";
2908
	}
2909
}
2910

    
2911
function interface_proxyarp_configure($interface = "") {
2912
	global $g;
2913
	if (config_get_path('system/developerspew')) {
2914
		$mt = microtime();
2915
		echo "interface_proxyarp_configure() being called $mt\n";
2916
	}
2917

    
2918
	/* kill any running choparp */
2919
	if (empty($interface)) {
2920
		killbyname("choparp");
2921
	} else {
2922
		$vipif = get_real_interface($interface);
2923
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2924
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2925
		}
2926
	}
2927

    
2928
	$paa = array();
2929
	$vips = config_get_path('virtualip/vip');
2930
	if (is_array($vips)) {
2931

    
2932
		/* group by interface */
2933
		foreach ($vips as $vipent) {
2934
			if ($vipent['mode'] === "proxyarp") {
2935
				if ($vipent['interface']) {
2936
					$proxyif = $vipent['interface'];
2937
				} else {
2938
					$proxyif = "wan";
2939
				}
2940

    
2941
				if (!empty($interface) && $interface != $proxyif) {
2942
					continue;
2943
				}
2944

    
2945
				if (!is_array($paa[$proxyif])) {
2946
					$paa[$proxyif] = array();
2947
				}
2948

    
2949
				$paa[$proxyif][] = $vipent;
2950
			}
2951
		}
2952
	}
2953

    
2954
	if (!empty($interface)) {
2955
		if (is_array($paa[$interface])) {
2956
			$paaifip = get_interface_ip($interface);
2957
			if (!is_ipaddr($paaifip)) {
2958
				return;
2959
			}
2960
			$vipif = get_real_interface($interface);
2961
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2962
			$args .= $vipif . " auto";
2963
			foreach ($paa[$interface] as $paent) {
2964
				if (isset($paent['subnet'])) {
2965
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2966
				} elseif (isset($paent['range'])) {
2967
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2968
				}
2969
			}
2970
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2971
		}
2972
	} elseif (count($paa) > 0) {
2973
		foreach ($paa as $paif => $paents) {
2974
			$paaifip = get_interface_ip($paif);
2975
			if (!is_ipaddr($paaifip)) {
2976
				continue;
2977
			}
2978
			$vipif = get_real_interface($paif);
2979
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2980
			$args .= $vipif . " auto";
2981
			foreach ($paents as $paent) {
2982
				if (isset($paent['subnet'])) {
2983
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2984
				} elseif (isset($paent['range'])) {
2985
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2986
				}
2987
			}
2988
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2989
		}
2990
	}
2991
}
2992

    
2993
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
2994
	$vips = config_get_path('virtualip/vip');
2995
	if (is_array($vips)) {
2996
		foreach ($vips as $vip) {
2997

    
2998
			$iface = $vip['interface'];
2999
			if (substr($iface, 0, 4) == "_vip")
3000
				$iface = get_configured_vip_interface($vip['interface']);
3001
			if ($iface != $interface)
3002
				continue;
3003
			if ($type == VIP_CARP) {
3004
				if ($vip['mode'] != "carp")
3005
					continue;
3006
			} elseif ($type == VIP_IPALIAS) {
3007
				if ($vip['mode'] != "ipalias")
3008
					continue;
3009
			} else {
3010
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
3011
					continue;
3012
			}
3013

    
3014
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
3015
				interface_vip_bring_down($vip);
3016
			elseif ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
3017
				interface_vip_bring_down($vip);
3018
			elseif ($inet == "all")
3019
				interface_vip_bring_down($vip);
3020
		}
3021
	}
3022
}
3023

    
3024
function interfaces_vips_configure($interface = "") {
3025
	if (config_get_path('system/developerspew')) {
3026
		$mt = microtime();
3027
		echo "interfaces_vips_configure() being called $mt\n";
3028
	}
3029

    
3030
	$vips = config_get_path('virtualip/vip');
3031
	if (!is_array($vips)) {
3032
		return;
3033
	}
3034

    
3035
	$carp_setuped = false;
3036
	$anyproxyarp = false;
3037
	foreach ($vips as $vip) {
3038
		if ($interface <> "" &&
3039
		    get_root_interface($vip['interface']) <> $interface) {
3040
			continue;
3041
		}
3042
		switch ($vip['mode']) {
3043
			case "proxyarp":
3044
				/*
3045
				 * nothing it is handled on
3046
				 * interface_proxyarp_configure()
3047
				 */
3048
				$anyproxyarp = true;
3049
				break;
3050
			case "ipalias":
3051
				interface_ipalias_configure($vip);
3052
				break;
3053
			case "carp":
3054
				if ($carp_setuped == false) {
3055
					$carp_setuped = true;
3056
				}
3057
				interface_carp_configure($vip);
3058
				break;
3059
		}
3060
	}
3061
	if ($carp_setuped == true) {
3062
		interfaces_sync_setup();
3063
	}
3064
	if ($anyproxyarp == true) {
3065
		interface_proxyarp_configure();
3066
	}
3067
}
3068

    
3069
function interface_ipalias_configure(&$vip) {
3070
	$gateway = '';
3071
	if ($vip['mode'] != 'ipalias') {
3072
		return;
3073
	}
3074

    
3075
	$realif = get_real_interface("_vip{$vip['uniqid']}");
3076
	if ($realif != "lo0") {
3077
		$if = convert_real_interface_to_friendly_interface_name($realif);
3078
		if (!config_path_enabled("interfaces/{$if}")) {
3079
			return;
3080
		}
3081
		if (is_pseudo_interface($realif)) {
3082
			if (is_ipaddrv4($vip['subnet'])) {
3083
				$gateway = get_interface_gateway($if);
3084
			} else {
3085
				$gateway = get_interface_gateway_v6($if);
3086
			}
3087
		}
3088
	}
3089

    
3090
	$af = 'inet';
3091
	if (is_ipaddrv6($vip['subnet'])) {
3092
		$af = 'inet6';
3093
	}
3094
	$iface = $vip['interface'];
3095
	$vhid = '';
3096
	if (substr($vip['interface'], 0, 4) == "_vip") {
3097
		$carpvip = get_configured_vip($vip['interface']);
3098
		$iface = $carpvip['interface'];
3099
		$vhid = "vhid {$carpvip['vhid']}";
3100
	}
3101
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$gateway} {$vhid}");
3102
	unset($iface, $af, $realif, $carpvip, $vhid, $gateway);
3103
}
3104

    
3105
function interface_carp_configure(&$vip, $maintenancemode_only = false, $ipalias_reload = false) {
3106
	global $config;
3107
	if (config_get_path('system/developerspew')) {
3108
		$mt = microtime();
3109
		echo "interface_carp_configure() being called $mt\n";
3110
	}
3111

    
3112
	if ($vip['mode'] != "carp") {
3113
		return;
3114
	}
3115

    
3116
	$realif = get_real_interface($vip['interface']);
3117
	if (!does_interface_exist($realif)) {
3118
		file_notice("CARP", sprintf(gettext(
3119
		    "Interface specified for the virtual IP address %s does not exist. Skipping this VIP."),
3120
		    $vip['subnet']), "Firewall: Virtual IP", "");
3121
		return;
3122
	}
3123
	if ($realif != "lo0") {
3124
		if (!config_path_enabled("interfaces/{$vip['interface']}")) {
3125
			return;
3126
		}
3127
	}
3128

    
3129
	$vip_password = $vip['password'];
3130
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3131
	    $vip_password)));
3132
	if ($vip['password'] != "") {
3133
		$password = " pass {$vip_password}";
3134
	}
3135

    
3136
	$advbase = "";
3137
	if (!empty($vip['advbase'])) {
3138
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3139
	}
3140

    
3141
	$carp_maintenancemode = isset(
3142
	    $config["virtualip_carp_maintenancemode"]);
3143
	if ($carp_maintenancemode) {
3144
		$advskew = "advskew 254";
3145
	} else {
3146
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3147
	}
3148

    
3149
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) .
3150
	    " {$advskew} {$advbase} {$password}");
3151

    
3152
	if (!$maintenancemode_only) {
3153
		if (is_ipaddrv4($vip['subnet'])) {
3154
			mwexec("/sbin/ifconfig {$realif} " .
3155
			    escapeshellarg($vip['subnet']) . "/" .
3156
			    escapeshellarg($vip['subnet_bits']) .
3157
			    " alias vhid " . escapeshellarg($vip['vhid']));
3158
		} elseif (is_ipaddrv6($vip['subnet'])) {
3159
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3160
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3161
			    escapeshellarg($vip['subnet_bits']) .
3162
			    " alias vhid " . escapeshellarg($vip['vhid']));
3163
		}
3164
	}
3165

    
3166
	/* reconfigure stacked IP Aliases after CARP VIP changes
3167
	 * see https://redmine.pfsense.org/issues/12227
3168
	 * and https://redmine.pfsense.org/issues/12961 */
3169
	if ($ipalias_reload) {
3170
		foreach ($config['virtualip']['vip'] as $viface) {
3171
			if (($viface['mode'] == 'ipalias') &&
3172
			    (get_root_interface($viface['interface']) == $vip['interface'])) { 
3173
				interface_vip_bring_down($viface);
3174
				interface_ipalias_configure($viface);
3175
			}
3176
		}
3177
	}
3178

    
3179
	return $realif;
3180
}
3181

    
3182
function interface_wireless_clone($realif, $wlcfg) {
3183
	global $g;
3184
	/*   Check to see if interface has been cloned as of yet.
3185
	 *   If it has not been cloned then go ahead and clone it.
3186
	 */
3187
	$needs_clone = false;
3188
	if (is_array($wlcfg['wireless'])) {
3189
		$wlcfg_mode = $wlcfg['wireless']['mode'];
3190
	} else {
3191
		$wlcfg_mode = $wlcfg['mode'];
3192
	}
3193
	switch ($wlcfg_mode) {
3194
		case "hostap":
3195
			$mode = "wlanmode hostap";
3196
			break;
3197
		case "adhoc":
3198
			$mode = "wlanmode adhoc";
3199
			break;
3200
		default:
3201
			$mode = "";
3202
			break;
3203
	}
3204
	$baseif = interface_get_wireless_base($wlcfg['if']);
3205
	if (does_interface_exist($realif)) {
3206
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
3207
		$ifconfig_str = implode($output);
3208
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
3209
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
3210
			$needs_clone = true;
3211
		}
3212
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
3213
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
3214
			$needs_clone = true;
3215
		}
3216
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
3217
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
3218
			$needs_clone = true;
3219
		}
3220
	} else {
3221
		$needs_clone = true;
3222
	}
3223

    
3224
	if ($needs_clone == true) {
3225
		/* remove previous instance if it exists */
3226
		if (does_interface_exist($realif)) {
3227
			pfSense_interface_destroy($realif);
3228

    
3229
			/* Invalidate cache */
3230
			get_interface_arr(true);
3231
		}
3232

    
3233
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
3234
		// Create the new wlan interface. FreeBSD returns the new interface name.
3235
		// example:  wlan2
3236
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
3237
		if ($ret <> 0) {
3238
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
3239
			return false;
3240
		}
3241
		$newif = trim($out[0]);
3242
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
3243
		pfSense_interface_rename($newif, $realif);
3244
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
3245
	}
3246
	return true;
3247
}
3248

    
3249
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3250
	global $config;
3251

    
3252
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3253
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3254
				 'regdomain', 'regcountry', 'reglocation');
3255

    
3256
	if (!is_interface_wireless($ifcfg['if'])) {
3257
		return;
3258
	}
3259

    
3260
	$baseif = interface_get_wireless_base($ifcfg['if']);
3261

    
3262
	// Sync shared settings for assigned clones
3263
	$iflist = get_configured_interface_list(true);
3264
	foreach ($iflist as $if) {
3265
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
3266
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
3267
				foreach ($shared_settings as $setting) {
3268
					if ($sync_changes) {
3269
						if (isset($ifcfg['wireless'][$setting])) {
3270
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
3271
						} elseif (isset($config['interfaces'][$if]['wireless'][$setting])) {
3272
							unset($config['interfaces'][$if]['wireless'][$setting]);
3273
						}
3274
					} else {
3275
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3276
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
3277
						} elseif (isset($ifcfg['wireless'][$setting])) {
3278
							unset($ifcfg['wireless'][$setting]);
3279
						}
3280
					}
3281
				}
3282
				if (!$sync_changes) {
3283
					break;
3284
				}
3285
			}
3286
		}
3287
	}
3288

    
3289
	// Read or write settings at shared area
3290
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
3291
		foreach ($shared_settings as $setting) {
3292
			if ($sync_changes) {
3293
				if (isset($ifcfg['wireless'][$setting])) {
3294
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
3295
				} elseif (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3296
					unset($config['wireless']['interfaces'][$baseif][$setting]);
3297
				}
3298
			} elseif (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3299
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3300
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
3301
				} elseif (isset($ifcfg['wireless'][$setting])) {
3302
					unset($ifcfg['wireless'][$setting]);
3303
				}
3304
			}
3305
		}
3306
	}
3307

    
3308
	// Sync the mode on the clone creation page with the configured mode on the interface
3309
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3310
		foreach ($config['wireless']['clone'] as &$clone) {
3311
			if ($clone['cloneif'] == $ifcfg['if']) {
3312
				if ($sync_changes) {
3313
					$clone['mode'] = $ifcfg['wireless']['mode'];
3314
				} else {
3315
					$ifcfg['wireless']['mode'] = $clone['mode'];
3316
				}
3317
				break;
3318
			}
3319
		}
3320
		unset($clone);
3321
	}
3322
}
3323

    
3324
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3325
	global $config, $g;
3326

    
3327
	/*    open up a shell script that will be used to output the commands.
3328
	 *    since wireless is changing a lot, these series of commands are fragile
3329
	 *    and will sometimes need to be verified by a operator by executing the command
3330
	 *    and returning the output of the command to the developers for inspection.  please
3331
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3332
	 */
3333

    
3334
	// Remove script file
3335
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3336

    
3337
	// Clone wireless nic if needed.
3338
	interface_wireless_clone($if, $wl);
3339

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

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

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

    
3349
	/* set values for /path/program */
3350
	if (file_exists("/usr/local/sbin/hostapd")) {
3351
		$hostapd = "/usr/local/sbin/hostapd";
3352
	} else {
3353
		$hostapd = "/usr/sbin/hostapd";
3354
	}
3355
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3356
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3357
	} else {
3358
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3359
	}
3360
	$ifconfig = "/sbin/ifconfig";
3361
	$sysctl = "/sbin/sysctl";
3362
	$sysctl_args = "-q";
3363

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

    
3366
	$wlcmd = array();
3367
	$wl_sysctl = array();
3368
	/* Set a/b/g standard */
3369
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3370
	/* skip mode entirely for "auto" */
3371
	if ($wlcfg['standard'] != "auto") {
3372
		$wlcmd[] = "mode " . escapeshellarg($standard);
3373
	}
3374

    
3375
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3376
	 * to prevent massive packet loss under certain conditions. */
3377
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3378
		$wlcmd[] = "-ampdu";
3379
	}
3380

    
3381
	/* Set ssid */
3382
	if ($wlcfg['ssid']) {
3383
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3384
	}
3385

    
3386
	/* Set 802.11g protection mode */
3387
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3388

    
3389
	/* set wireless channel value */
3390
	if (isset($wlcfg['channel'])) {
3391
		if ($wlcfg['channel'] == "0") {
3392
			$wlcmd[] = "channel any";
3393
		} else {
3394
			if ($wlcfg['channel_width'] != "0") {
3395
				$channel_width = ":" . $wlcfg['channel_width'];
3396
			} else {
3397
				$channel_width = '';
3398
			}
3399
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3400
		}
3401
	}
3402

    
3403
	/* Set antenna diversity value */
3404
	if (isset($wlcfg['diversity'])) {
3405
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3406
	}
3407

    
3408
	/* Set txantenna value */
3409
	if (isset($wlcfg['txantenna'])) {
3410
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3411
	}
3412

    
3413
	/* Set rxantenna value */
3414
	if (isset($wlcfg['rxantenna'])) {
3415
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3416
	}
3417

    
3418
	/* set Distance value */
3419
	if ($wlcfg['distance']) {
3420
		$distance = escapeshellarg($wlcfg['distance']);
3421
	}
3422

    
3423
	/* Set wireless hostap mode */
3424
	if ($wlcfg['mode'] == "hostap") {
3425
		$wlcmd[] = "mediaopt hostap";
3426
	} else {
3427
		$wlcmd[] = "-mediaopt hostap";
3428
	}
3429

    
3430
	/* Set wireless adhoc mode */
3431
	if ($wlcfg['mode'] == "adhoc") {
3432
		$wlcmd[] = "mediaopt adhoc";
3433
	} else {
3434
		$wlcmd[] = "-mediaopt adhoc";
3435
	}
3436

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

    
3439
	/* handle hide ssid option */
3440
	if (isset($wlcfg['hidessid']['enable'])) {
3441
		$wlcmd[] = "hidessid";
3442
	} else {
3443
		$wlcmd[] = "-hidessid";
3444
	}
3445

    
3446
	/* handle pureg (802.11g) only option */
3447
	if (isset($wlcfg['pureg']['enable'])) {
3448
		$wlcmd[] = "mode 11g pureg";
3449
	} else {
3450
		$wlcmd[] = "-pureg";
3451
	}
3452

    
3453
	/* handle puren (802.11n) only option */
3454
	if (isset($wlcfg['puren']['enable'])) {
3455
		$wlcmd[] = "puren";
3456
	} else {
3457
		$wlcmd[] = "-puren";
3458
	}
3459

    
3460
	/* enable apbridge option */
3461
	if (isset($wlcfg['apbridge']['enable'])) {
3462
		$wlcmd[] = "apbridge";
3463
	} else {
3464
		$wlcmd[] = "-apbridge";
3465
	}
3466

    
3467
	/* handle turbo option */
3468
	if (isset($wlcfg['turbo']['enable'])) {
3469
		$wlcmd[] = "mediaopt turbo";
3470
	} else {
3471
		$wlcmd[] = "-mediaopt turbo";
3472
	}
3473

    
3474
	/* handle txpower setting */
3475
	// or don't. this has issues at the moment.
3476
	/*
3477
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3478
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3479
	}*/
3480

    
3481
	/* handle wme option */
3482
	if (isset($wlcfg['wme']['enable'])) {
3483
		$wlcmd[] = "wme";
3484
	} else {
3485
		$wlcmd[] = "-wme";
3486
	}
3487

    
3488
	/* Enable wpa if it's configured. No WEP support anymore. */
3489
	if (isset($wlcfg['wpa']['enable'])) {
3490
		$wlcmd[] = "authmode wpa wepmode off ";
3491
	} else {
3492
		$wlcmd[] = "authmode open wepmode off ";
3493
	}
3494

    
3495
	kill_hostapd($if);
3496
	mwexec(kill_wpasupplicant("{$if}"));
3497

    
3498
	$wpa_supplicant_file = "{$g['varetc_path']}/wpa_supplicant_{$if}.";
3499
	$hostapd_conf = "{$g['varetc_path']}/hostapd_{$if}.conf";
3500

    
3501
	unlink_if_exists("{$wpa_supplicant_file}*");
3502
	unlink_if_exists($hostapd_conf);
3503

    
3504
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3505
	$wpa = "";
3506
	switch ($wlcfg['mode']) {
3507
		case 'bss':
3508
			if (isset($wlcfg['wpa']['enable'])) {
3509
				$wpa .= <<<EOD
3510
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3511
ctrl_interface_group=0
3512
ap_scan=1
3513
#fast_reauth=1
3514
network={
3515
ssid="{$wlcfg['ssid']}"
3516
scan_ssid=1
3517
priority=5
3518
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3519
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3520
group={$wlcfg['wpa']['wpa_pairwise']}
3521

    
3522
EOD;
3523
				if ($wlcfg['wpa']['wpa_key_mgmt'] == 'WPA-EAP') {
3524
					if (($wlcfg['wpa']['wpa_eap_client_mode'] == 'PEAP') ||
3525
					    ($wlcfg['wpa']['wpa_eap_client_mode'] == 'TTLS')) {
3526
						if ($wlcfg['wpa']['wpa_eap_inner_auth'] == 'MSCHAPV2') {
3527
							$wpa .= "phase1=\"peaplabel=0\"\n";
3528
						}
3529
						$wpa .= "phase2=\"auth={$wlcfg['wpa']['wpa_eap_inner_auth']}\"\n";
3530
						$wpa .= "identity=\"{$wlcfg['wpa']['wpa_eap_inner_id']}\"\n";
3531
						$eappass = base64_decode($wlcfg['wpa']['wpa_eap_inner_password']);
3532
						$wpa .= "password=\"{$eappass}\"\n";
3533
					}
3534
					if (strstr($wlcfg['wpa']['wpa_eap_client_mode'], 'TLS')) { 
3535
						$cert = lookup_cert($wlcfg['wpa']['wpa_eap_cert']);
3536
						$wpa_supplicant_crt = $wpa_supplicant_file . "crt";
3537
						$wpa_supplicant_key = $wpa_supplicant_file . "key";
3538
						@file_put_contents($wpa_supplicant_crt, base64_decode($cert['crt']) . "\n" .
3539
						    ca_chain($cert)); 
3540
						@file_put_contents($wpa_supplicant_key, base64_decode($cert['prv'])); 
3541
						@chmod($wpa_supplicant_crt, 0600);
3542
						@chmod($wpa_supplicant_key, 0600);
3543
						$wpa .= "client_cert=\"{$wpa_supplicant_crt}\"\n";
3544
						$wpa .= "private_key=\"{$wpa_supplicant_key}\"\n";
3545
					}
3546
					$ca = lookup_ca($wlcfg['wpa']['wpa_eap_ca']);
3547
					$wpa_supplicant_ca = $wpa_supplicant_file . "ca";
3548
					@file_put_contents($wpa_supplicant_ca, base64_decode($ca['crt']) . "\n" .
3549
					    ca_chain($ca)); 
3550
					$wpa .= "ca_cert=\"{$wpa_supplicant_ca}\"\n";
3551
					$wpa .= "eap={$wlcfg['wpa']['wpa_eap_client_mode']}\n";
3552
				} else {
3553
					$wpa .= "psk=\"{$wlcfg['wpa']['passphrase']}\"\n";
3554
				}
3555
				$wpa .= "}\n";
3556

    
3557
				@file_put_contents($wpa_supplicant_file . "conf", $wpa);
3558
				unset($wpa);
3559
			}
3560
			break;
3561
		case 'hostap':
3562
			if (!empty($wlcfg['wpa']['passphrase'])) {
3563
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3564
			} else {
3565
				$wpa_passphrase = "";
3566
			}
3567
			if (isset($wlcfg['wpa']['enable'])) {
3568
				$wpa .= <<<EOD
3569
interface={$if}
3570
driver=bsd
3571
logger_syslog=-1
3572
logger_syslog_level=0
3573
logger_stdout=-1
3574
logger_stdout_level=0
3575
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3576
ctrl_interface={$g['varrun_path']}/hostapd
3577
ctrl_interface_group=wheel
3578
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3579
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3580
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3581
ssid={$wlcfg['ssid']}
3582
debug={$wlcfg['wpa']['debug_mode']}
3583
wpa={$wlcfg['wpa']['wpa_mode']}
3584
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3585
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3586
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3587
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3588
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3589
{$wpa_passphrase}
3590

    
3591
EOD;
3592

    
3593
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3594
					$wpa .= <<<EOD
3595
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3596
rsn_preauth=1
3597
rsn_preauth_interfaces={$if}
3598

    
3599
EOD;
3600
				}
3601
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3602
					$wpa .= "ieee8021x=1\n";
3603

    
3604
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3605
						$auth_server_port = "1812";
3606
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3607
							$auth_server_port = intval($wlcfg['auth_server_port']);
3608
						}
3609
						$wpa .= <<<EOD
3610

    
3611
auth_server_addr={$wlcfg['auth_server_addr']}
3612
auth_server_port={$auth_server_port}
3613
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3614

    
3615
EOD;
3616
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3617
							$auth_server_port2 = "1812";
3618
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3619
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3620
							}
3621

    
3622
							$wpa .= <<<EOD
3623
auth_server_addr={$wlcfg['auth_server_addr2']}
3624
auth_server_port={$auth_server_port2}
3625
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3626

    
3627
EOD;
3628
						}
3629
					}
3630
				}
3631

    
3632
				@file_put_contents($hostapd_conf, $wpa);
3633
				unset($wpa);
3634
			}
3635
			break;
3636
	}
3637

    
3638
	/*
3639
	 *    all variables are set, lets start up everything
3640
	 */
3641

    
3642
	$baseif = interface_get_wireless_base($if);
3643
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3644
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3645

    
3646
	/* set sysctls for the wireless interface */
3647
	if (!empty($wl_sysctl)) {
3648
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3649
		foreach ($wl_sysctl as $wl_sysctl_line) {
3650
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3651
		}
3652
	}
3653

    
3654
	/* set ack timers according to users preference (if he/she has any) */
3655
	if ($distance) {
3656
		fwrite($fd_set, "# Enable ATH distance settings\n");
3657
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3658
	}
3659

    
3660
	if (isset($wlcfg['wpa']['enable'])) {
3661
		if ($wlcfg['mode'] == "bss") {
3662
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3663
		}
3664
		if ($wlcfg['mode'] == "hostap") {
3665
			/* add line to script to restore old mac to make hostapd happy */
3666
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3667
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3668
				$if_curmac = get_interface_mac($if);
3669
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3670
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3671
						" link " . escapeshellarg($if_oldmac) . "\n");
3672
				}
3673
			}
3674

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

    
3677
			/* add line to script to restore spoofed mac after running hostapd */
3678
			if ($wl['spoofmac']) {
3679
				$if_curmac = get_interface_mac($if);
3680
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3681
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3682
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3683
				}
3684
			}
3685
		}
3686
	}
3687

    
3688
	fclose($fd_set);
3689

    
3690
	/* Making sure regulatory settings have actually changed
3691
	 * before applying, because changing them requires bringing
3692
	 * down all wireless networks on the interface. */
3693
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3694
	$ifconfig_str = implode($output);
3695
	unset($output);
3696
	$reg_changing = false;
3697

    
3698
	/* special case for the debug country code */
3699
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3700
		$reg_changing = true;
3701
	} elseif ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3702
		$reg_changing = true;
3703
	} elseif ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3704
		$reg_changing = true;
3705
	} elseif ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3706
		$reg_changing = true;
3707
	} elseif ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3708
		$reg_changing = true;
3709
	}
3710

    
3711
	if ($reg_changing) {
3712
		/* set regulatory domain */
3713
		if ($wlcfg['regdomain']) {
3714
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3715
		}
3716

    
3717
		/* set country */
3718
		if ($wlcfg['regcountry']) {
3719
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3720
		}
3721

    
3722
		/* set location */
3723
		if ($wlcfg['reglocation']) {
3724
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3725
		}
3726

    
3727
		$wlregcmd_args = implode(" ", $wlregcmd);
3728

    
3729
		/* build a complete list of the wireless clones for this interface */
3730
		$clone_list = array();
3731
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3732
			$clone_list[] = interface_get_wireless_clone($baseif);
3733
		}
3734
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3735
			foreach ($config['wireless']['clone'] as $clone) {
3736
				if ($clone['if'] == $baseif) {
3737
					$clone_list[] = $clone['cloneif'];
3738
				}
3739
			}
3740
		}
3741

    
3742
		/* find which clones are up and bring them down */
3743
		$clones_up = array();
3744
		foreach ($clone_list as $clone_if) {
3745
			$clone_status = get_interface_addresses($clone_if);
3746
			if ($clone_status['status'] == 'up') {
3747
				$clones_up[] = $clone_if;
3748
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3749
			}
3750
		}
3751

    
3752
		/* apply the regulatory settings */
3753
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3754
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3755

    
3756
		/* bring the clones back up that were previously up */
3757
		foreach ($clones_up as $clone_if) {
3758
			interfaces_bring_up($clone_if);
3759

    
3760
			/*
3761
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3762
			 * is in infrastructure mode, and WPA is enabled.
3763
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3764
			 */
3765
			if ($clone_if != $if) {
3766
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3767
				if ((!empty($friendly_if)) &&
3768
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3769
				    config_path_enabled("interfaces/{$friendly_if}/wireless/wpa")) {
3770
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3771
				}
3772
			}
3773
		}
3774
	}
3775

    
3776
	/* The mode must be specified in a separate command before ifconfig
3777
	 * will allow the mode and channel at the same time in the next.
3778
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3779
	 */
3780
	if ($wlcfg['mode'] == "hostap") {
3781
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3782
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3783
	}
3784

    
3785
	/* configure wireless */
3786
	$wlcmd_args = implode(" ", $wlcmd);
3787
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args);
3788
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3789
	/* Bring the interface up only after setting up all the other parameters. */
3790
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up");
3791
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3792
	fclose($wlan_setup_log);
3793

    
3794
	unset($wlcmd_args, $wlcmd);
3795

    
3796

    
3797
	sleep(1);
3798
	/* execute hostapd and wpa_supplicant if required in shell */
3799
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3800

    
3801
	return 0;
3802

    
3803
}
3804

    
3805
function kill_hostapd($interface) {
3806
	global $g;
3807

    
3808
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3809
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3810
	}
3811
}
3812

    
3813
function kill_wpasupplicant($interface) {
3814
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3815
}
3816

    
3817
function find_dhclient_process($interface) {
3818
	if ($interface) {
3819
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3820
	} else {
3821
		$pid = 0;
3822
	}
3823

    
3824
	return intval($pid);
3825
}
3826

    
3827
function kill_dhclient_process($interface) {
3828
	if (empty($interface) || !does_interface_exist($interface)) {
3829
		return;
3830
	}
3831

    
3832
	$i = 0;
3833
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3834
		/* 3rd time make it die for sure */
3835
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3836
		posix_kill($pid, $sig);
3837
		sleep(1);
3838
		$i++;
3839
	}
3840
	unset($i);
3841
}
3842

    
3843
function find_dhcp6c_process() {
3844
	global $g;
3845

    
3846
	if (isvalidpid("{$g['varrun_path']}/dhcp6c.pid")) {
3847
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c.pid"), " \n");
3848
	} else {
3849
		return(false);
3850
	}
3851

    
3852
	return intval($pid);
3853
}
3854

    
3855
function kill_dhcp6client_process($force, $release = false) {
3856
	global $g;
3857

    
3858
	$i = 0;
3859

    
3860
	/*
3861
	Beware of the following: Reason, the interface may be down, but
3862
	dhcp6c may still be running, it just complains it cannot send
3863
	and carries on. Commented out as will stop the call to kill.
3864

    
3865
	if (empty($interface) || !does_interface_exist($interface)) {
3866
		return;
3867
	}
3868
	*/
3869

    
3870
	/*********** Notes on signals for dhcp6c and this function *************
3871

    
3872
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3873
	a release and waiting for the response that never comes.
3874
	So we need to tell it that the interface is down and to just die quickly
3875
	otherwise a new client may launch and we have duplicate proceses.
3876
	In this case use SIGUSR1.
3877

    
3878
	If we want to exit normally obeying the no release flag then use SIGTERM.
3879
	If we want to exit with a release overiding the no release flag then
3880
	use SIGUSR2.
3881

    
3882
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3883
	exit quickly without sending release signals.
3884

    
3885
	If $Force is set to false and $release is also set to false dhcp6c will
3886
	follow the no-release flag.
3887

    
3888
	If $Force is set to false and $release is true then dhcp6c will send a
3889
	release regardless of the no-release flag.
3890
	***********************************************************************/
3891

    
3892
	if ($force == true) {
3893
		$psig=SIGUSR1;
3894
	} elseif ($release == false) {
3895
		$psig=SIGTERM;
3896
	} else {
3897
		$psig=SIGUSR2;
3898
	}
3899

    
3900
	while ((($pid = find_dhcp6c_process()) != 0) && ($i < 3)) {
3901
		/* 3rd time make it die for sure */
3902
		$sig = ($i == 2 ? SIGKILL : $psig);
3903
		posix_kill($pid, $sig);
3904
		sleep(1);
3905
		$i++;
3906
	}
3907
	/* Clear the RTSOLD script created lock & tidy up */
3908
	unlink_if_exists("/tmp/dhcp6c_lock");
3909
	unlink_if_exists("{$g['varrun_path']}/dhcp6c.pid"); // just in case!
3910
}
3911
function reset_dhcp6client_process() {
3912

    
3913
	$pid = find_dhcp6c_process();
3914

    
3915
	if($pid != 0) {
3916
		posix_kill($pid, SIGHUP);
3917
	}
3918
}
3919

    
3920
function run_dhcp6client_process($interfaces, $debugOptions, $noreleaseOption) {
3921
	global $g;
3922

    
3923
	/*
3924
	 * Only run this if the lock does not exist. In theory the lock being
3925
	 * there in this mode means the user has selected dhcp6withoutRA while
3926
	 * a session is active in the other mode.
3927
	 *
3928
	 * It should not happen as the process should have been killed and the
3929
	 * lock deleted.
3930
	 */
3931

    
3932
	if (!file_exists("/tmp/dhcp6c_lock")) {
3933
		kill_dhcp6client_process(true);
3934
		/* Lock it to avoid multiple runs */
3935
		touch("/tmp/dhcp6c_lock");
3936
		mwexec("/usr/local/sbin/dhcp6c {$debugOptions} " .
3937
		    "{$noreleaseOption} " .
3938
		    "-c {$g['varetc_path']}/dhcp6c.conf " .
3939
		    "-p {$g['varrun_path']}/dhcp6c.pid " .
3940
		    implode(' ', $interfaces));
3941
		log_error(sprintf(gettext(
3942
		    "Starting DHCP6 client for interfaces %s in DHCP6 without RA mode"),
3943
		    implode(',', $interfaces)));
3944
	}
3945
}
3946

    
3947
function interface_virtual_create($interface, $gateways_status = false) {
3948
	global $config;
3949

    
3950
	/* Fetch gateway status if not passed */
3951
	if (!is_array($gateways_status)) {
3952
		$gateways_status = return_gateways_status(true);
3953
	}
3954

    
3955
	if (interface_is_vlan($interface) != NULL) {
3956
		interface_vlan_configure(interface_is_vlan($interface));
3957
	} elseif (substr($interface, 0, 3) == "gre") {
3958
		interfaces_tunnel_configure(0, $interface, 'gre');
3959
	} elseif (substr($interface, 0, 3) == "gif") {
3960
		interfaces_tunnel_configure(0, $interface, 'gif');
3961
	} elseif (substr($interface, 0, 5) == "ovpns") {
3962
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3963
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3964
				if ($interface == "ovpns{$server['vpnid']}") {
3965
					if (!function_exists('openvpn_resync')) {
3966
						require_once('openvpn.inc');
3967
					}
3968
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3969
					openvpn_resync('server', $server);
3970
				}
3971
			}
3972
			unset($server);
3973
		}
3974
	} elseif (substr($interface, 0, 5) == "ovpnc") {
3975
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
3976
			foreach ($config['openvpn']['openvpn-client'] as $client) {
3977
				if ($interface == "ovpnc{$client['vpnid']}") {
3978
					if (!function_exists('openvpn_resync')) {
3979
						require_once('openvpn.inc');
3980
					}
3981
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
3982
					openvpn_resync('client', $client);
3983
				}
3984
			}
3985
			unset($client);
3986
		}
3987
	} elseif (substr($interface, 0, 5) == "ipsec") {
3988
		if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
3989
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
3990
				if ($ph1ent['disabled']) {
3991
					continue;
3992
				}
3993
				interface_ipsec_vti_configure($ph1ent, $gateways_status);
3994
			}
3995
		}
3996
	} elseif (substr($interface, 0, 4) == "lagg") {
3997
		interfaces_lagg_configure($interface);
3998
	} elseif (substr($interface, 0, 6) == "bridge") {
3999
		interfaces_bridge_configure(0, $interface);
4000
	}
4001
}
4002

    
4003
function interface_vlan_mtu_configured($iface) {
4004
	global $config;
4005

    
4006
	$mtu = 0;
4007
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
4008
		foreach ($config['vlans']['vlan'] as $vlan) {
4009

    
4010
			if ($vlan['vlanif'] != $iface)
4011
				continue;
4012

    
4013
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4014
			$parentinf = convert_real_interface_to_friendly_interface_name($vlan['if']);
4015
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
4016
				/* VLAN MTU */
4017
				$mtu = $config['interfaces'][$assignedport]['mtu'];
4018
			} elseif (!empty($config['interfaces'][$parentinf]['mtu'])) {
4019
				/* Parent MTU */
4020
				$mtu = $config['interfaces'][$parentinf]['mtu'];
4021
			}
4022
		}
4023
	}
4024

    
4025
	return $mtu;
4026
}
4027

    
4028
function interface_mtu_wanted_for_pppoe($realif) {
4029
	global $config;
4030

    
4031
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
4032
		return 0;
4033

    
4034
	$mtu = 0;
4035
	foreach ($config['ppps']['ppp'] as $ppp) {
4036
		if ($ppp['type'] != "pppoe") {
4037
			continue;
4038
		}
4039

    
4040
		$mtus = array();
4041
		if (!empty($ppp['mtu'])) {
4042
			$mtus = explode(',', $ppp['mtu']);
4043
		}
4044
		$ports = explode(',', $ppp['ports']);
4045

    
4046
		foreach ($ports as $pid => $port) {
4047
			$parentifa = get_parent_interface($port);
4048
			$parentif = $parentifa[0];
4049
			if ($parentif != $realif)
4050
				continue;
4051

    
4052
			// there is an MTU configured on the port in question
4053
			if (!empty($mtus[$pid])) {
4054
				$mtu = intval($mtus[$pid]) + 8;
4055
			// or use the MTU configured on the interface ...
4056
			} elseif (is_array($config['interfaces'])) {
4057
				foreach ($config['interfaces'] as $interface) {
4058
					if ($interface['if'] == $ppp['if'] &&
4059
					    !empty($interface['mtu'])) {
4060
						$mtu = intval($interface['mtu']) + 8;
4061
						break;
4062
					}
4063
				}
4064
			}
4065
		}
4066
	}
4067

    
4068
	return $mtu;
4069
}
4070

    
4071
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
4072
	global $config, $g;
4073
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
4074
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
4075

    
4076
	$wancfg = config_get_path("interfaces/{$interface}");
4077

    
4078
	if (!isset($wancfg['enable'])) {
4079
		return;
4080
	}
4081

    
4082
	$realif = get_real_interface($interface);
4083
	$realhwif_array = get_parent_interface($interface);
4084
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
4085
	$realhwif = $realhwif_array[0];
4086

    
4087
	$mac_if_cfg = $wancfg;
4088
	if (interface_is_vlan($realif)) {
4089
		$mac_if = convert_real_interface_to_friendly_interface_name(
4090
		    $realhwif);
4091
		if (is_array(config_get_path("interfaces/{$mac_if}"))) {
4092
			$mac_if_cfg = config_get_path("interfaces/{$mac_if}");
4093
		} else {
4094
			$mac_if = $interface;
4095
		}
4096
	}
4097

    
4098
	if (!platform_booting() && (substr($realif, 0, 4) != "ovpn") && (substr($realif, 0, 5) != "ipsec")) {
4099
		/* remove all IPv4 and IPv6 addresses */
4100
		$tmpifaces = pfSense_getall_interface_addresses($realif);
4101
		if (is_array($tmpifaces)) {
4102
			foreach ($tmpifaces as $tmpiface) {
4103
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
4104
					if (!is_linklocal($tmpiface)) {
4105
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
4106
					}
4107
				} elseif (strstr($tmpiface, "fe80::1:1")) {
4108
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 fe80::1:1 -alias");
4109
				} else {
4110
					if (is_subnetv4($tmpiface)) {
4111
						$tmpip = explode('/', $tmpiface);
4112
						$tmpip = $tmpip[0];
4113
					} else {
4114
						$tmpip = $tmpiface;
4115
					}
4116
					pfSense_interface_deladdress($realif, $tmpip);
4117
				}
4118
			}
4119
		}
4120

    
4121
		/* only bring down the interface when both v4 and v6 are set to NONE */
4122
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
4123
			interface_bring_down($interface);
4124
		}
4125
	}
4126

    
4127
	$interface_to_check = $realif;
4128
	if (interface_isppp_type($interface)) {
4129
		$interface_to_check = $realhwif;
4130
	}
4131

    
4132
	/* Need to check that the interface exists or not in the case where its coming back from disabled state see #3270 */
4133
	if (!platform_booting() && (in_array(substr($realif, 0, 3), array("gre", "gif")) ||
4134
	    !does_interface_exist($interface_to_check))) {
4135
		interface_virtual_create($interface_to_check);
4136
	}
4137

    
4138
	/* Disable Accepting router advertisements unless specifically requested */
4139
	if ($g['debug']) {
4140
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
4141
	}
4142
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
4143
	{
4144
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
4145
	}
4146
	/* wireless configuration? */
4147
	if (is_array($wancfg['wireless']) && !$linkupevent) {
4148
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
4149
	}
4150

    
4151
	$current_mac = get_interface_mac($realhwif);
4152
	$vendor_mac = get_interface_vendor_mac($realhwif);
4153

    
4154
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
4155
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
4156

    
4157
		interface_set_macaddr($realhwif, $mac_addr);
4158

    
4159
		/* Regenerate link-local address on MAC change.
4160
		 *
4161
		 * Some network devices respond to a DHCPv6 Solicit message only when
4162
		 * the IPv6 source address is consistent with what they expect.
4163
		 *
4164
		 * See https://redmine.pfsense.org/issues/12794 */
4165
		if ($mac_addr != $current_mac) {
4166
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 ifdisabled");
4167
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 " . get_interface_linklocal($interface) . " delete");
4168
			mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -ifdisabled");
4169
		}
4170
	} else {
4171
		/*
4172
		 * this is not a valid mac address.  generate a
4173
		 * temporary mac address so the machine can get online.
4174
		 */
4175
		echo gettext("Generating new MAC address.");
4176
		$random_mac = generate_random_mac_address();
4177
		interface_set_macaddr($realhwif, $random_mac);
4178
		$config['interfaces'][$mac_if]['spoofmac'] = $random_mac;
4179
		write_config(sprintf(gettext('The invalid MAC address ' .
4180
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
4181
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
4182
		file_notice("MAC Address altered", sprintf(gettext('The ' .
4183
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
4184
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
4185
		    $random_mac), "Interfaces");
4186
	}
4187

    
4188
	/* media */
4189
	if ($wancfg['media'] || $wancfg['mediaopt']) {
4190
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
4191
		if ($wancfg['media']) {
4192
			$cmd .= " media " . escapeshellarg($wancfg['media']);
4193
		}
4194
		if ($wancfg['mediaopt']) {
4195
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
4196
		}
4197
		mwexec($cmd);
4198
	}
4199

    
4200
	/* Apply hw offloading policies as configured */
4201
	enable_hardware_offloading($interface);
4202

    
4203
	/* invalidate interface/ip/sn cache */
4204
	get_interface_arr(true);
4205
	unset($interface_ip_arr_cache[$realif]);
4206
	unset($interface_sn_arr_cache[$realif]);
4207
	unset($interface_ipv6_arr_cache[$realif]);
4208
	unset($interface_snv6_arr_cache[$realif]);
4209

    
4210
	$tunnelif = substr($realif, 0, 3);
4211

    
4212
	$mtuif = $realif;
4213
	$mtuhwif = $realhwif;
4214

    
4215
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
4216
	if (interface_isppp_type($interface)) {
4217
		$mtuif = $realhwif;
4218
		$mtuhwif_array = get_parent_interface($mtuif);
4219
		$mtuhwif = $mtuhwif_array[0];
4220
	}
4221

    
4222
	$wantedmtu = 0;
4223
	if (is_array($config['interfaces'])) {
4224
		foreach ($config['interfaces'] as $tmpinterface) {
4225
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
4226
				$wantedmtu = $tmpinterface['mtu'];
4227
				break;
4228
			}
4229
		}
4230
	}
4231

    
4232
	/* MTU is not specified for interface, try the pppoe settings. */
4233
	if ($wantedmtu == 0) {
4234
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
4235
	}
4236
	if (($wantedmtu == 0) && (interface_is_vlan($mtuif) != NULL) && interface_isppp_type($interface)) {
4237
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
4238
	}
4239
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gre')) {
4240
		/* set MTU to 1400 for GRE over IPsec */
4241
		if (is_greipsec($mtuif)) {
4242
			$wantedmtu = 1400;
4243
		} else {
4244
			$wantedmtu = 1476;
4245
		}
4246
	}
4247
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gif')) {
4248
		$wantedmtu = 1280;
4249
	}
4250

    
4251
	/* Set the MTU to 1500 if no explicit MTU configured. */
4252
	if ($wantedmtu == 0) {
4253
		$wantedmtu = 1500; /* Default */
4254
	}
4255

    
4256
	if (interface_is_vlan($mtuif) != NULL) {
4257
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4258
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
4259
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
4260
			if ($wancfg['mtu'] > $parentmtu) {
4261
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4262
			}
4263
		}
4264

    
4265
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4266

    
4267
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4268
			$configuredmtu = $parentmtu;
4269
		if ($configuredmtu != 0)
4270
			$mtu = $configuredmtu;
4271
		else
4272
			$mtu = $wantedmtu;
4273

    
4274
		/* Set the parent MTU. */
4275
		if (get_interface_mtu($mtuhwif) < $mtu)
4276
			set_interface_mtu($mtuhwif, $mtu);
4277
		/* Set the VLAN MTU. */
4278
		if (get_interface_mtu($mtuif) != $mtu)
4279
			set_interface_mtu($mtuif, $mtu);
4280
	} elseif (substr($mtuif, 0, 4) == 'lagg') {
4281
		/* LAGG interface must be destroyed and re-created to change MTU */
4282
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4283
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
4284
				foreach ($config['laggs']['lagg'] as $lagg) {
4285
					if ($lagg['laggif'] == $mtuif) {
4286
						interface_lagg_configure($lagg);
4287
						break;
4288
					}
4289
				}
4290
			}
4291
		}
4292
	} else {
4293
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4294
			pfSense_interface_mtu($mtuif, $wantedmtu);
4295
			set_ipv6routes_mtu($mtuif, $wantedmtu);
4296
		}
4297
	}
4298
	/* XXX: What about gre/gif/.. ? */
4299

    
4300
	if (does_interface_exist($wancfg['if'])) {
4301
		interfaces_bring_up($wancfg['if']);
4302
	}
4303

    
4304
	switch ($wancfg['ipaddr']) {
4305
		case 'dhcp':
4306
			interface_dhcp_configure($interface);
4307
			break;
4308
		case 'pppoe':
4309
		case 'l2tp':
4310
		case 'pptp':
4311
		case 'ppp':
4312
			interface_ppps_configure($interface);
4313
			break;
4314
		default:
4315
			/* XXX: Kludge for now related to #3280 */
4316
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips", "l2t"))) {
4317
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
4318
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
4319
				}
4320
			}
4321
			break;
4322
	}
4323

    
4324
	switch ($wancfg['ipaddrv6']) {
4325
		case 'slaac':
4326
		case 'dhcp6':
4327
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
4328
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
4329
			// handles all non-PPP connections with 'dhcp6usev4iface' set
4330
			log_error(gettext("calling interface_dhcpv6_configure."));
4331
			if ((($wancfg['ipaddrv6'] == 'dhcp6') && !isset($wancfg['dhcp6usev4iface'])) ||
4332
			    (($wancfg['ipaddrv6'] == 'slaac') && !isset($wancfg['slaacusev4iface'])) ||
4333
			    !interface_isppp_type($interface)) {
4334
				interface_dhcpv6_configure($interface, $wancfg);
4335
			}
4336
			break;
4337
		case '6rd':
4338
			interface_6rd_configure($interface, $wancfg);
4339
			break;
4340
		case '6to4':
4341
			interface_6to4_configure($interface, $wancfg);
4342
			break;
4343
		case 'track6':
4344
			interface_track6_configure($interface, $wancfg, $linkupevent);
4345
			break;
4346
		default:
4347
			/* XXX: Kludge for now related to #3280 */
4348
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips", "l2t"))) {
4349
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
4350
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
4351
					// FIXME: Add IPv6 Support to the pfSense module
4352
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
4353
				}
4354
			}
4355
			break;
4356
	}
4357

    
4358
	if (!platform_booting()) {
4359
		link_interface_to_vips($interface, "update");
4360

    
4361
		if ($tunnelif != 'gre') {
4362
			$gre = link_interface_to_tunnelif($interface, 'gre');
4363
			array_walk($gre, 'interface_gre_configure');
4364
		}
4365

    
4366
		if ($tunnelif != 'gif') {
4367
			$gif = link_interface_to_tunnelif($interface, 'gif');
4368
			array_walk($gif, 'interface_gif_configure');
4369
		}
4370

    
4371
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4372
			unset($bridgetmp);
4373
			$bridgetmp = link_interface_to_bridge($interface);
4374
			if (!empty($bridgetmp)) {
4375
				interface_bridge_add_member($bridgetmp, $realif);
4376
			}
4377
		}
4378

    
4379
		$grouptmp = link_interface_to_group($interface);
4380
		if (!empty($grouptmp)) {
4381
			array_walk($grouptmp, 'interface_group_add_member');
4382
		}
4383

    
4384
		if ($interface == "lan") {
4385
			/* make new hosts file */
4386
			system_hosts_generate();
4387
		}
4388

    
4389
		if ($reloadall == true) {
4390

    
4391
			/* reconfigure static routes (kernel may have deleted them) */
4392
			system_routing_configure($interface);
4393

    
4394
			/* reload ipsec tunnels */
4395
			send_event("service reload ipsecdns");
4396

    
4397
			if (config_path_enabled('dnsmasq')) {
4398
				services_dnsmasq_configure();
4399
			}
4400

    
4401
			if (config_path_enabled('unbound')) {
4402
				services_unbound_configure();
4403
			}
4404

    
4405
			/* update dyndns */
4406
			send_event("service reload dyndns {$interface}");
4407
		}
4408
	} 
4409

    
4410
	if (!platform_booting() && (substr($realif, 0, 5) == 'l2tps')) {
4411
		vpn_l2tp_configure();
4412
	};
4413

    
4414
	if (!empty($wancfg['descr'])) {
4415
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4416
	};
4417

    
4418
	interfaces_staticarp_configure($interface);
4419
	return 0;
4420
}
4421

    
4422
function interface_track6_configure($interface, $wancfg, $linkupevent = false) {
4423
	global $config, $g;
4424

    
4425
	if (!is_array($wancfg)) {
4426
		return;
4427
	}
4428

    
4429
	if (!isset($wancfg['enable'])) {
4430
		return;
4431
	}
4432

    
4433
	/* If the interface is not configured via another, exit */
4434
	if (empty($wancfg['track6-interface'])) {
4435
		return;
4436
	}
4437

    
4438
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4439
	$realif = get_real_interface($interface);
4440
	$linklocal = find_interface_ipv6_ll($realif, true);
4441
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4442
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4443
	}
4444

    
4445
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4446
	if (!isset($trackcfg['enable'])) {
4447
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4448
		return;
4449
	}
4450

    
4451
	$type = $trackcfg['ipaddrv6'];
4452
	switch ($type) {
4453
		case "6to4":
4454
			if ($g['debug']) {
4455
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4456
			}
4457
			interface_track6_6to4_configure($interface, $wancfg);
4458
			break;
4459
		case "6rd":
4460
			if ($g['debug']) {
4461
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4462
			}
4463
			interface_track6_6rd_configure($interface, $wancfg);
4464
			break;
4465
		case "dhcp6":
4466
			if ($linkupevent == true) {
4467
				/*
4468
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4469
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4470
				 *
4471
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4472
				 */
4473
				$pidv6 = find_dhcp6c_process();
4474
				if ($pidv6) {
4475
					posix_kill($pidv6, SIGHUP);
4476
				}
4477
			}
4478
			break;
4479
	}
4480

    
4481
	if ($linkupevent == false && !platform_booting()) {
4482
		if (!function_exists('services_dhcpd_configure')) {
4483
			require_once("services.inc");
4484
		}
4485

    
4486
		/* restart dns servers (defering dhcpd reload) */
4487
		if (config_path_enabled('unbound')) {
4488
			services_unbound_configure(false);
4489
		}
4490
		if (config_path_enabled('dnsmasq')) {
4491
			services_dnsmasq_configure(false);
4492
		}
4493

    
4494
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4495
		services_dhcpd_configure("inet6");
4496
	}
4497

    
4498
	return 0;
4499
}
4500

    
4501
function interface_track6_6rd_configure($interface, $lancfg) {
4502
	global $config;
4503
	global $interface_ipv6_arr_cache;
4504
	global $interface_snv6_arr_cache;
4505

    
4506
	if (!is_array($lancfg)) {
4507
		return;
4508
	}
4509

    
4510
	/* If the interface is not configured via another, exit */
4511
	if (empty($lancfg['track6-interface'])) {
4512
		return;
4513
	}
4514

    
4515
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4516
	if (empty($wancfg)) {
4517
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4518
		return;
4519
	}
4520

    
4521
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4522
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4523
		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']));
4524
		return;
4525
	}
4526
	$hexwanv4 = return_hex_ipv4($ip4address);
4527

    
4528
	/* create the long prefix notation for math, save the prefix length */
4529
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4530
	$rd6prefixlen = $rd6prefix[1];
4531
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4532

    
4533
	/* binary presentation of the prefix for all 128 bits. */
4534
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4535

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

    
4541
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4542
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4543
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4544
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4545
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4546
	/* fill the rest out with zeros */
4547
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4548

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

    
4552
	$lanif = get_real_interface($interface);
4553
	$oip = find_interface_ipv6($lanif);
4554
	if (is_ipaddrv6($oip)) {
4555
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4556
	}
4557
	unset($interface_ipv6_arr_cache[$lanif]);
4558
	unset($interface_snv6_arr_cache[$lanif]);
4559
	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));
4560
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4561

    
4562
	return 0;
4563
}
4564

    
4565
function interface_track6_6to4_configure($interface, $lancfg) {
4566
	global $config;
4567
	global $interface_ipv6_arr_cache;
4568
	global $interface_snv6_arr_cache;
4569

    
4570
	if (!is_array($lancfg)) {
4571
		return;
4572
	}
4573

    
4574
	/* If the interface is not configured via another, exit */
4575
	if (empty($lancfg['track6-interface'])) {
4576
		return;
4577
	}
4578

    
4579
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4580
	if (empty($wancfg)) {
4581
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4582
		return;
4583
	}
4584

    
4585
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4586
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4587
		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']));
4588
		return;
4589
	}
4590
	$hexwanv4 = return_hex_ipv4($ip4address);
4591

    
4592
	/* create the long prefix notation for math, save the prefix length */
4593
	$sixto4prefix = "2002::";
4594
	$sixto4prefixlen = 16;
4595
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4596

    
4597
	/* binary presentation of the prefix for all 128 bits. */
4598
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4599

    
4600
	/* just save the left prefix length bits */
4601
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4602
	/* add the v4 address */
4603
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4604
	/* add the custom prefix id */
4605
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4606
	/* fill the rest out with zeros */
4607
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4608

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

    
4612
	$lanif = get_real_interface($interface);
4613
	$oip = find_interface_ipv6($lanif);
4614
	if (is_ipaddrv6($oip)) {
4615
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4616
	}
4617
	unset($interface_ipv6_arr_cache[$lanif]);
4618
	unset($interface_snv6_arr_cache[$lanif]);
4619
	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));
4620
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4621

    
4622
	return 0;
4623
}
4624

    
4625
function interface_6rd_configure($interface, $wancfg) {
4626
	global $g;
4627

    
4628
	/* because this is a tunnel interface we can only function
4629
	 *	with a public IPv4 address on the interface */
4630

    
4631
	if (!is_array($wancfg)) {
4632
		return;
4633
	}
4634

    
4635
	if (!is_module_loaded('if_stf.ko')) {
4636
		mwexec('/sbin/kldload if_stf.ko');
4637
	}
4638

    
4639
	$wanif = get_real_interface($interface);
4640
	$ip4address = find_interface_ip($wanif);
4641
	if (!is_ipaddrv4($ip4address)) {
4642
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4643
		return false;
4644
	}
4645
	$hexwanv4 = return_hex_ipv4($ip4address);
4646

    
4647
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4648
		$wancfg['prefix-6rd-v4plen'] = 0;
4649
	}
4650

    
4651
	/* create the long prefix notation for math, save the prefix length */
4652
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4653
	$rd6prefixlen = $rd6prefix[1];
4654
	$brgw = explode('.', $wancfg['gateway-6rd']);
4655
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4656
	$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);
4657
	if (strlen($rd6brgw) < 128) {
4658
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4659
	}
4660
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4661
	unset($brgw);
4662
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4663

    
4664
	/* binary presentation of the prefix for all 128 bits. */
4665
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4666

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

    
4674
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4675
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4676

    
4677

    
4678
	/* XXX: need to extend to support variable prefix size for v4 */
4679
	$stfiface = "{$interface}_stf";
4680
	if (does_interface_exist($stfiface)) {
4681
		pfSense_interface_destroy($stfiface);
4682
	}
4683
	$tmpstfiface = pfSense_interface_create2("stf");
4684
	pfSense_interface_rename($tmpstfiface, $stfiface);
4685
	pfSense_interface_flags($stfiface, IFF_LINK2);
4686
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4687
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4688
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4689
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4690
	}
4691
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4692
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4693
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4694
	} elseif ($parentmtu > 1300) {
4695
		set_interface_mtu($stfiface, $parentmtu - 20);
4696
	}
4697
	if ($g['debug']) {
4698
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4699
	}
4700

    
4701
	/* write out a default router file */
4702
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4703
	unlink_if_exists("{$g['tmp_path']}/{$wanif}_routerv6.last");
4704
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4705

    
4706
	$ip4gateway = get_interface_gateway($interface);
4707
	if (is_ipaddrv4($ip4gateway)) {
4708
		route_add_or_change($wancfg['gateway-6rd'], $ip4gateway);
4709
	}
4710

    
4711
	/* configure dependent interfaces */
4712
	if (!platform_booting()) {
4713
		link_interface_to_track6($interface, "update");
4714
	}
4715

    
4716
	return 0;
4717
}
4718

    
4719
function interface_6to4_configure($interface, $wancfg) {
4720
	global $g;
4721

    
4722
	/* because this is a tunnel interface we can only function
4723
	 *	with a public IPv4 address on the interface */
4724

    
4725
	if (!is_array($wancfg)) {
4726
		return;
4727
	}
4728

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

    
4736
	/* create the long prefix notation for math, save the prefix length */
4737
	$stfprefixlen = 16;
4738
	$stfprefix = Net_IPv6::uncompress("2002::");
4739
	$stfarr = explode(":", $stfprefix);
4740
	$v4prefixlen = "0";
4741

    
4742
	/* we need the hex form of the interface IPv4 address */
4743
	$ip4arr = explode(".", $ip4address);
4744
	$hexwanv4 = "";
4745
	foreach ($ip4arr as $octet) {
4746
		$hexwanv4 .= sprintf("%02x", $octet);
4747
	}
4748

    
4749
	/* we need the hex form of the broker IPv4 address */
4750
	$ip4arr = explode(".", "192.88.99.1");
4751
	$hexbrv4 = "";
4752
	foreach ($ip4arr as $octet) {
4753
		$hexbrv4 .= sprintf("%02x", $octet);
4754
	}
4755

    
4756
	/* binary presentation of the prefix for all 128 bits. */
4757
	$stfprefixbin = "";
4758
	foreach ($stfarr as $element) {
4759
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4760
	}
4761
	/* just save the left prefix length bits */
4762
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4763

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

    
4768
	/* for the local subnet too. */
4769
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4770
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4771

    
4772
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4773
	$stfbrarr = array();
4774
	$stfbrbinarr = array();
4775
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4776
	foreach ($stfbrbinarr as $bin) {
4777
		$stfbrarr[] = dechex(bindec($bin));
4778
	}
4779
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4780

    
4781
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4782
	$stflanarr = array();
4783
	$stflanbinarr = array();
4784
	$stflanbinarr = str_split($stflanbin, 16);
4785
	foreach ($stflanbinarr as $bin) {
4786
		$stflanarr[] = dechex(bindec($bin));
4787
	}
4788
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4789
	$stflanarr[7] = 1;
4790

    
4791
	/* setup the stf interface */
4792
	if (!is_module_loaded("if_stf")) {
4793
		mwexec("/sbin/kldload if_stf.ko");
4794
	}
4795
	$stfiface = "{$interface}_stf";
4796
	if (does_interface_exist($stfiface)) {
4797
		pfSense_interface_destroy($stfiface);
4798
	}
4799
	$tmpstfiface = pfSense_interface_create2("stf");
4800
	pfSense_interface_rename($tmpstfiface, $stfiface);
4801
	pfSense_interface_flags($stfiface, IFF_LINK2);
4802
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4803

    
4804
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4805
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4806
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4807
	} elseif ($parentmtu > 1300) {
4808
		set_interface_mtu($stfiface, $parentmtu - 20);
4809
	}
4810
	if ($g['debug']) {
4811
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4812
	}
4813

    
4814
	/* write out a default router file */
4815
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4816
	unlink_if_exists("{$g['tmp_path']}/{$wanif}_routerv6.last");
4817
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4818

    
4819
	$ip4gateway = get_interface_gateway($interface);
4820
	if (is_ipaddrv4($ip4gateway)) {
4821
		route_add_or_change("192.88.99.1", $ip4gateway);
4822
	}
4823

    
4824
	if (!platform_booting()) {
4825
		link_interface_to_track6($interface, "update");
4826
	}
4827

    
4828
	return 0;
4829
}
4830

    
4831
function interface_dhcpv6_configure($ifconf, $ifcfg, $destroy = false) {
4832
	global $config, $g;
4833

    
4834
	$dhcp6cconf = "";
4835
	$id = "0";
4836
	$dhcp6cinterfaces = array();
4837
	$dhcp6cifs_descr = array();
4838
	$dhcp6crealifs = array();
4839
	$debugOption = "-d";
4840
	$noreleaseOption = "";
4841

    
4842
	if (!empty($config['system']['global-v6duid'])) {
4843
		// Write the DUID file
4844
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4845
		    log_error(gettext("Failed to write user DUID file!"));
4846
		}
4847
	}
4848

    
4849
	foreach ($config['interfaces'] as $interface => $wancfg) {
4850
		$wanif = get_real_interface($interface, "inet6");
4851

    
4852
		if (($ifconf == $interface) && $destroy) {
4853
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
4854
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh");
4855
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$wanif}_script.sh");
4856
			continue;
4857
		}
4858

    
4859
		if (!isset($wancfg['enable']) || (($ifconf == $interface) && $destroy) ||
4860
		    (($wancfg['ipaddrv6'] != 'dhcp6') && ($wancfg['ipaddrv6'] != 'slaac'))) {
4861
			continue;
4862
		}
4863

    
4864
		$dhcp6cinterfaces[$interface] = $wancfg;
4865

    
4866
		if (isset($config['system']['dhcp6debug'])) {
4867
			$debugOption = "-D";
4868
		}
4869
		if (isset($config['system']['dhcp6norelease'])) {
4870
			$noreleaseOption = "-n";
4871
		}
4872

    
4873
		/* accept router advertisements for this interface                 */
4874
		/* Moved to early in the function as sometimes interface not ready */
4875
		/* RTSOLD fails as interface does not accept .....                 */
4876

    
4877
		log_error("Accept router advertisements on interface {$wanif} ");
4878
		mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4879

    
4880
		if ($wancfg['adv_dhcp6_config_file_override']) {
4881
			// DHCP6 Config File Override
4882
			$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4883
		} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4884
			// DHCP6 Config File Advanced
4885
			$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4886
		} else {
4887
			// DHCP6 Config File Basic
4888
			$dhcp6cconf .= "interface {$wanif} {\n";
4889

    
4890
			/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4891
			if ($wancfg['ipaddrv6'] == "slaac") {
4892
				$dhcp6cconf .= "\tinformation-only;\n";
4893
				$dhcp6cconf .= "\trequest domain-name-servers;\n";
4894
				$dhcp6cconf .= "\trequest domain-name;\n";
4895
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4896
				$dhcp6cconf .= "};\n";
4897
			} else {
4898
				$trackiflist = array();
4899
				$iflist = link_interface_to_track6($interface);
4900
				foreach ($iflist as $ifname => $ifcfg) {
4901
					if (is_numeric($ifcfg['track6-prefix-id'])) {
4902
						$trackiflist[$ifname] = $ifcfg;
4903
					}
4904
				}
4905

    
4906
				/* skip address request if this is set */
4907
				if (!isset($wancfg['dhcp6prefixonly'])) {
4908
					$dhcp6cconf .= "\tsend ia-na {$id};\t# request stateful address\n";
4909
				}
4910
				if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4911
					$dhcp6cconf .= "\tsend ia-pd {$id};\t# request prefix delegation\n";
4912
				}
4913

    
4914
				$dhcp6cconf .= "\trequest domain-name-servers;\n";
4915
				$dhcp6cconf .= "\trequest domain-name;\n";
4916

    
4917
				/*
4918
				 * dhcp6c will run different scripts depending on
4919
				 * whether dhcpwithoutra is set or unset.
4920
				 */
4921
				if (isset($wancfg['dhcp6withoutra'])) {
4922
					$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4923
				} else {
4924
					$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4925
				}
4926
				$dhcp6cconf .= "};\n";
4927

    
4928
				if (!isset($wancfg['dhcp6prefixonly'])) {
4929
					$dhcp6cconf .= "id-assoc na {$id} { };\n";
4930
				}
4931

    
4932
				if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4933
					/* Setup the prefix delegation */
4934
					$dhcp6cconf .= "id-assoc pd {$id} {\n";
4935
					$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4936
					if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4937
						$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4938
					}
4939
					foreach ($trackiflist as $friendly => $ifcfg) {
4940
						if ($g['debug']) {
4941
							log_error("setting up $interface - {$ifcfg['track6-prefix-id']}");
4942
						}
4943
						$realif = get_real_interface($friendly);
4944
						$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4945
						$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4946
						$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4947
						$dhcp6cconf .= "\t};\n";
4948
					}
4949
					unset($preflen, $iflist, $ifcfg, $ifname);
4950
					$dhcp6cconf .= "};\n\n";
4951
				}
4952
				unset($trackiflist);
4953
			}
4954
			$id++;
4955
		}
4956

    
4957
		/*************** Script Debug Logging ***************************
4958
		Both dhcp6 scripts now have a logging message built in.
4959
		These logging messages ONLY appear if dhcp6c debug logging is set.
4960
		The logging messages appear in the dhcp section of the logs,
4961
		not in system.
4962

    
4963
		These scripts now also take advantage of the REASON= env vars
4964
		supplied by dhcp6c.
4965
		****************************************************************/
4966

    
4967
		/* Script create for dhcp6withoutRA mode */
4968
		/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
4969
		$dhcp6cscriptwithoutra = "#!/bin/sh\n";
4970
		$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4971
		$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4972
		$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4973
		$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
4974
		// Need to pass params to  the final script
4975
		$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4976
		$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4977
		$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
4978
		$dhcp6cscriptwithoutra .= "case \$REASON in\n";
4979
		$dhcp6cscriptwithoutra .= "REQUEST)\n";
4980
		$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
4981
		$dhcp6cscriptwithoutra .= "/usr/sbin/rtsold -1 -p {$g['varrun_path']}/rtsold_{$wanif}.pid -M {$g['varetc_path']}/rtsold_{$wanif}_script.sh -O {$g['varetc_path']}/rtsold_{$wanif}_script.sh {$wanif}\n";
4982
		if ($debugOption == '-D') {
4983
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rtsold\"\n";
4984
		}
4985
		$dhcp6cscriptwithoutra .= ";;\n";
4986
		$dhcp6cscriptwithoutra .= "REBIND)\n";
4987
		if ($debugOption == '-D') {
4988
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
4989
		}
4990
		$dhcp6cscriptwithoutra .= ";;\n";
4991
		if (isset($wancfg['dhcp6norelease'])) {
4992
			$dhcp6cscriptwithoutra .= "EXIT)\n";
4993
		} else {
4994
			$dhcp6cscriptwithoutra .= "RELEASE)\n";
4995
		}
4996
		if ($debugOption == '-D') {
4997
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
4998
		}
4999
		$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5000
		$dhcp6cscriptwithoutra .= ";;\n";
5001
		$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
5002
		if ($debugOption == '-D') {
5003
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5004
		}
5005
		$dhcp6cscriptwithoutra .= "esac\n";
5006
		if (!@file_put_contents(
5007
		    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
5008
		    $dhcp6cscriptwithoutra)) {
5009
			printf("Error: cannot open " .
5010
			    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
5011
			    "interface_dhcpv6_configure() for writing.\n");
5012
			unset($dhcp6cscriptwithoutra);
5013
			return 1;
5014
		}
5015

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

    
5018
		/*
5019
		 * Dual mode wan_dhcp6c script with variations depending on node
5020
		 * dhcp6 will run the wan ipv6 configure
5021
		 */
5022
		$dhcp6cscript  = "#!/bin/sh\n";
5023
		$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
5024
		if (!isset($wancfg['dhcp6withoutra'])) {
5025
			$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
5026
			$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
5027
			$dhcp6cscript .= "case \$REASON in\n";
5028
			$dhcp6cscript .= "REBIND)\n";
5029
			if ($debugOption == '-D') {
5030
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
5031
			}
5032
			$dhcp6cscript .= ";;\n";
5033
			$dhcp6cscript .= "REQUEST|";
5034
			if (isset($wancfg['dhcp6norelease'])) {
5035
				$dhcp6cscript .= "EXIT)\n";
5036
			} else {
5037
				$dhcp6cscript .= "RELEASE)\n";
5038
			}
5039
			if ($debugOption == '-D') {
5040
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c RELEASE, REQUEST or EXIT on {$wanif} running rc.newwanipv6\"\n";
5041
			}
5042
			$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5043
			$dhcp6cscript .= ";;\n";
5044
			$dhcp6cscript .= "RENEW|INFO)\n";
5045
			if ($debugOption == '-D') {
5046
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5047
			}
5048
			$dhcp6cscript .= "esac\n";
5049
			$rtsold_ra_ifs[] = $wanif;
5050
		} else {
5051
			// Need to get the parameters from the dhcp6cwithoutRA run
5052
			$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
5053
			$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
5054
			$dhcp6cscript .= "/bin/sleep 1\n";
5055
			$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5056
		}
5057

    
5058
		/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5059
		if (!@file_put_contents("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", $dhcp6cscript)) {
5060
			printf("Error: cannot open dhcp6c_{$interface}_script.sh in interface_dhcpv6_configure() for writing.\n");
5061
			unset($dhcp6cscript);
5062
			return 1;
5063
		}
5064
		unset($dhcp6cscript);
5065
		@chmod("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh", 0755);
5066
	}
5067

    
5068
	if (!empty($dhcp6cinterfaces)) {
5069
		/* wide-dhcp6c works for now. */
5070
		if (!@file_put_contents("{$g['varetc_path']}/dhcp6c.conf", $dhcp6cconf)) {
5071
			printf("Error: cannot open dhcp6c.conf in interface_dhcpv6_configure() for writing.\n");
5072
			return 1;
5073
		}
5074
		foreach ($dhcp6cinterfaces as $interface => $wancfg) {
5075
			$dhcp6cifs_descr[] = $interface . '(' . $wancfg['if'] . ')';
5076
			$dhcp6crealifs[] = $wancfg['if'];
5077
		}
5078
		$dhcp6cdescr = implode(',', $dhcp6cifs_descr);
5079
		$dhcp6cifs = implode(' ', $dhcp6crealifs);
5080
		foreach ($dhcp6cinterfaces as $interface => $wancfg) {
5081
			$wanif = get_real_interface($interface, "inet6");
5082

    
5083
			$rtsoldscript_header = <<<EOD
5084
#!/bin/sh
5085
# This shell script launches dhcp6c and configured gateways for this interface.
5086
if [ -n "\$2" ]; then
5087
	if [ -n "$(echo \$2 | /usr/bin/grep '^fe80')" ]; then
5088
		echo \$2\%{$wanif} > {$g['tmp_path']}/{$wanif}_routerv6
5089
		/bin/rm -f {$g['tmp_path']}/{$wanif}_routerv6.last
5090
		echo \$2\%{$wanif} > {$g['tmp_path']}/{$wanif}_defaultgwv6
5091
	else
5092
		echo \$2 > {$g['tmp_path']}/{$wanif}_routerv6
5093
		/bin/rm -f {$g['tmp_path']}/{$wanif}_routerv6.last
5094
		echo \$2 > {$g['tmp_path']}/{$wanif}_defaultgwv6
5095
	fi
5096
	/usr/bin/logger -t rtsold "Received RA specifying route \$2 for interface {$interface}({$wanif})"
5097
fi
5098

    
5099
EOD;
5100

    
5101
			/* non ipoe Process */
5102
			$rtsoldscript = $rtsoldscript_header;
5103
			if (!isset($wancfg['dhcp6withoutra'])) {
5104
				/*
5105
				 * We only want this script to run once, and if it runs twice
5106
				 * then do not launch dhcp6c again, this only happens if
5107
				 * dhcpwithoutra is not set.
5108
				 *
5109
				 * Check for a lock file, trying to prevent multiple instances
5110
				 * of dhcp6c being launched
5111
				 */
5112
				$rtsoldscript .= "if [ ! -f /tmp/dhcp6c_lock ]; then\n";
5113
				/*
5114
				 * Create the lock file, trying to prevent multiple instances
5115
				 * of dhcp6c being launched
5116
				 */
5117
				$rtsoldscript .= "\t/usr/bin/touch /tmp/dhcp6c_lock\n";
5118
				$rtsoldscript .= "\tif [ -f {$g['varrun_path']}/dhcp6c.pid ]; then\n";
5119
				$rtsoldscript .= "\t\t/bin/pkill -F {$g['varrun_path']}/dhcp6c.pid\n";
5120
				$rtsoldscript .= "\t\t/bin/rm -f {$g['varrun_path']}/dhcp6c.pid\n";
5121
				$rtsoldscript .= "\t\t/bin/sleep 1\n";
5122
				$rtsoldscript .= "\tfi\n";
5123
				$rtsoldscript .= "\t/usr/local/sbin/dhcp6c {$debugOption} " .
5124
				    "{$noreleaseOption} -c {$g['varetc_path']}/dhcp6c.conf " .
5125
				    "-p {$g['varrun_path']}/dhcp6c.pid {$dhcp6cifs}\n";
5126
				$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"Starting dhcp6 client for interfaces {$dhcp6cdescr}\"\n";
5127
				$rtsoldscript .= "else\n";
5128
				$rtsoldscript .= "\t/usr/bin/logger -t rtsold \"RTSOLD Lock in place - sending SIGHUP to dhcp6c\"\n";
5129
				$rtsoldscript .= "\tdhcp6c_pid=\$(cat \"{$g['varrun_path']}/dhcp6c.pid\")\n";
5130
				$rtsoldscript .= "\t/bin/kill -1 \${dhcp6c_pid}\n";
5131
				$rtsoldscript .= "fi\n";
5132
			} else {
5133
				/*
5134
				 * The script needs to run in dhcp6withoutra mode as RA may
5135
				 * not have been received, or there can be a delay with
5136
				 * certain ISPs
5137
				 */
5138
				$rtsoldscript .= "{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\n";
5139
				$rtsoldscript .= "/bin/sleep 1\n";
5140
			}
5141

    
5142
			/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5143
			if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
5144
				printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
5145
				return 1;
5146
			}
5147
			unset($rtsoldscript);
5148
			@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
5149
		}
5150

    
5151
		$realif = get_real_interface($ifconf, "inet6");
5152
		if (isvalidpid("{$g['varrun_path']}/rtsold_{$realif}.pid")) {
5153
			killbypid("{$g['varrun_path']}/rtsold_{$realif}.pid");
5154
			log_error("Killing running rtsold process");
5155
			sleep(2);
5156
		}
5157

    
5158
		if (file_exists("{$g['tmp_path']}/dhcp6c_ifs")) {
5159
			$dhcp6crealifs_run = unserialize(file_get_contents("{$g['tmp_path']}/dhcp6c_ifs"));
5160
		} else {
5161
			$dhcp6crealifs_run = array();
5162
		}
5163

    
5164
		if (($dhcp6crealifs != $dhcp6crealifs_run) || $destroy) {
5165
			kill_dhcp6client_process(false);
5166
			run_dhcp6client_process($dhcp6crealifs, $debugOption, $noreleaseOption);
5167
			file_put_contents("{$g['tmp_path']}/dhcp6c_ifs", serialize($dhcp6crealifs));
5168
			$dhcp6c_restarted = true;
5169
			if ($destroy) {
5170
				$track6 = link_interface_to_track6($ifconf);
5171
				if (is_array($track6) && !empty($track6)) {
5172
					/* remove stale track interfaces IP */
5173
					foreach (array_keys($track6) as $tr6if) {
5174
						interface_reconfigure($tr6if, true);
5175
					}
5176
				}
5177
			}
5178
		}
5179

    
5180
		if (isset($ifcfg['dhcp6withoutra']) && !$dhcp6c_restarted) {
5181
			/*
5182
			 * Start dhcp6c here if we don't want to wait for ra - calls
5183
			 * separate function
5184
			 *
5185
			 * In this mode dhcp6c launches rtsold via its script. RTSOLD
5186
			 * will then run the configure on receipt of the RA.
5187
			 *
5188
			 * Already started. interface_dhcpv6_configure() appears to get
5189
			 * called multiple times.
5190
			 *
5191
			 * Taking the interface down or releasing will kill the client.
5192
			 */
5193

    
5194
			/*
5195
			 * If the interface is being brought up, wait for the
5196
			 * interface to configure accept RA before launching.
5197
			 * Otherwise it is not ready to accept and will fail.
5198
			 */
5199
			sleep(3);
5200
			if (file_exists("/tmp/dhcp6c_lock")) {
5201
				reset_dhcp6client_process();
5202
			}
5203
		} elseif (!$destroy) {
5204
			/*
5205
			 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
5206
			 * ( it does not background, it exits! ) It will launch dhcp6c
5207
			 * if dhcpwihtoutra is not set
5208
			 */
5209
			log_error("Starting rtsold process on {$ifconf}({$realif})");
5210
			sleep(2);
5211
			mwexec("/usr/sbin/rtsold -1 " .
5212
			    "-p {$g['varrun_path']}/rtsold_{$realif}.pid " .
5213
			    "-M {$g['varetc_path']}/rtsold_{$realif}_script.sh " .
5214
			    "-O {$g['varetc_path']}/rtsold_{$realif}_script.sh " .
5215
			    $realif);
5216
		}
5217
	} else {
5218
		kill_dhcp6client_process(true);
5219
		unlink_if_exists("{$g['varetc_path']}/dhcp6c.conf");
5220
		unlink_if_exists("{$g['tmp_path']}/dhcp6c_ifs");
5221
	}
5222

    
5223
	/*
5224
	 * NOTE: will be called from rtsold invoked script
5225
	 * link_interface_to_track6($interface, "update");
5226
	 */
5227

    
5228
	return 0;
5229
}
5230

    
5231
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5232
	global $g;
5233

    
5234
	$send_options = "";
5235
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
5236
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
5237
		foreach ($options as $option) {
5238
			$send_options .= "\tsend " . trim($option) . ";\n";
5239
		}
5240
	}
5241

    
5242
	$request_options = "";
5243
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5244
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5245
		foreach ($options as $option) {
5246
			$request_options .= "\trequest " . trim($option) . ";\n";
5247
		}
5248
	}
5249

    
5250
	$information_only = "";
5251
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5252
		$information_only = "\tinformation-only;\n";
5253
	}
5254

    
5255
	if (isset($wancfg['dhcp6withoutra'])) {
5256
		$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\";\n";
5257
	} else {
5258
		$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5259
	}
5260
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5261
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5262
	}
5263

    
5264
	$interface_statement  = "interface";
5265
	$interface_statement .= " {$wanif}";
5266
	$interface_statement .= " {\n";
5267
	$interface_statement .= "$send_options";
5268
	$interface_statement .= "$request_options";
5269
	$interface_statement .= "$information_only";
5270
	$interface_statement .= "$script";
5271
	$interface_statement .= "};\n";
5272

    
5273
	$id_assoc_statement_address = "";
5274
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5275
		$id_assoc_statement_address .= "id-assoc";
5276
		$id_assoc_statement_address .= " na";
5277
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5278
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5279
		}
5280
		$id_assoc_statement_address .= " { ";
5281

    
5282
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5283
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5284
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5285
			$id_assoc_statement_address .= "\n\taddress";
5286
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5287
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5288
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5289
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5290
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5291
			}
5292
			$id_assoc_statement_address .= ";\n";
5293
		}
5294

    
5295
		$id_assoc_statement_address .= "};\n";
5296
	}
5297

    
5298
	$id_assoc_statement_prefix = "";
5299
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5300
		$id_assoc_statement_prefix .= "id-assoc";
5301
		$id_assoc_statement_prefix .= " pd";
5302
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5303
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5304
		}
5305
		$id_assoc_statement_prefix .= " { ";
5306

    
5307
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5308
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5309
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5310
			$id_assoc_statement_prefix .= "\n\tprefix";
5311
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5312
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5313
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5314
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5315
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5316
			}
5317
			$id_assoc_statement_prefix .= ";";
5318
		}
5319

    
5320
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
5321
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
5322
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
5323
			$id_assoc_statement_prefix .= " {$realif}";
5324
			$id_assoc_statement_prefix .= " {\n";
5325
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
5326
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
5327
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
5328
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
5329
			}
5330
			$id_assoc_statement_prefix .= "\t};";
5331
		}
5332

    
5333
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5334
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5335
			$id_assoc_statement_prefix .= "\n";
5336
		}
5337

    
5338
		$id_assoc_statement_prefix .= "};\n";
5339
	}
5340

    
5341
	$authentication_statement = "";
5342
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
5343
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
5344
		$authentication_statement .= "authentication";
5345
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
5346
		$authentication_statement .= " {\n";
5347
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
5348
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
5349
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
5350
		}
5351
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
5352
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
5353
		}
5354
		$authentication_statement .= "};\n";
5355
	}
5356

    
5357
	$key_info_statement = "";
5358
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5359
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5360
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5361
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5362
		$key_info_statement .= "keyinfo";
5363
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5364
		$key_info_statement .= " {\n";
5365
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5366
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5367
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5368
		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'])) {
5369
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5370
		}
5371
		$key_info_statement .= "};\n";
5372
	}
5373

    
5374
	$dhcp6cconf  = $interface_statement;
5375
	$dhcp6cconf .= $id_assoc_statement_address;
5376
	$dhcp6cconf .= $id_assoc_statement_prefix;
5377
	$dhcp6cconf .= $authentication_statement;
5378
	$dhcp6cconf .= $key_info_statement;
5379

    
5380
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5381

    
5382
	return $dhcp6cconf;
5383
}
5384

    
5385

    
5386
function DHCP6_Config_File_Override($wancfg, $wanif) {
5387

    
5388
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5389

    
5390
	if ($dhcp6cconf === false) {
5391
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5392
		return '';
5393
	} else {
5394
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5395
	}
5396
}
5397

    
5398

    
5399
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5400

    
5401
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5402

    
5403
	return $dhcp6cconf;
5404
}
5405

    
5406

    
5407
function interface_dhcp_configure($interface) {
5408
	global $g, $vlanprio_values;
5409

    
5410
	$ifcfg = config_get_path("interfaces/{$interface}");
5411
	if (empty($ifcfg)) {
5412
		$ifcfg = array();
5413
	}
5414

    
5415
	$dhclientconf_vlantag = "";
5416
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5417
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5418
	}
5419

    
5420
	/* generate dhclient_wan.conf */
5421
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5422
	if (!$fd) {
5423
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5424
		return 1;
5425
	}
5426

    
5427
	if ($ifcfg['dhcphostname']) {
5428
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5429
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5430
	} else {
5431
		$dhclientconf_hostname = "";
5432
	}
5433

    
5434
	$realif = get_real_interface($interface);
5435
	if (empty($realif)) {
5436
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5437
		return 0;
5438
	}
5439
	$dhclientconf = "";
5440

    
5441
	$dhclientconf .= <<<EOD
5442
interface "{$realif}" {
5443
	supersede interface-mtu 0;
5444
	timeout 60;
5445
	retry 15;
5446
	select-timeout 0;
5447
	initial-interval 1;
5448
	{$dhclientconf_vlantag}
5449
	{$dhclientconf_hostname}
5450
	script "/usr/local/sbin/pfSense-dhclient-script";
5451
EOD;
5452

    
5453
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5454
		$dhclientconf .= <<<EOD
5455

    
5456
	reject {$ifcfg['dhcprejectfrom']};
5457
EOD;
5458
	}
5459
	$dhclientconf .= <<<EOD
5460

    
5461
}
5462

    
5463
EOD;
5464

    
5465
	// DHCP Config File Advanced
5466
	if ($ifcfg['adv_dhcp_config_advanced']) {
5467
		$dhclientconf = DHCP_Config_File_Advanced($ifcfg, $realif);
5468
	}
5469

    
5470
	if (is_ipaddr($ifcfg['alias-address'])) {
5471
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5472
		$dhclientconf .= <<<EOD
5473
alias {
5474
	interface "{$realif}";
5475
	fixed-address {$ifcfg['alias-address']};
5476
	option subnet-mask {$subnetmask};
5477
}
5478

    
5479
EOD;
5480
	}
5481

    
5482
	// DHCP Config File Override
5483
	if ($ifcfg['adv_dhcp_config_file_override']) {
5484
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5485
	}
5486

    
5487
	fwrite($fd, $dhclientconf);
5488
	fclose($fd);
5489

    
5490
	/* bring wan interface up before starting dhclient */
5491
	if ($realif) {
5492
		interfaces_bring_up($realif);
5493
	}
5494

    
5495
	/* Make sure dhclient is not running */
5496
	kill_dhclient_process($realif);
5497

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

    
5501
	return 0;
5502
}
5503

    
5504
function DHCP_Config_File_Advanced($ifcfg, $realif) {
5505

    
5506
	$hostname = "";
5507
	if ($ifcfg['dhcphostname'] != '') {
5508
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5509
	}
5510

    
5511
	/* DHCP Protocol Timings */
5512
	$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");
5513
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5514
		$pt_variable = "{$Protocol_Timing}";
5515
		${$pt_variable} = "";
5516
		if ($ifcfg[$Protocol_Timing] != "") {
5517
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5518
		}
5519
	}
5520

    
5521
	$send_options = "";
5522
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5523
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5524
		foreach ($options as $option) {
5525
			$send_options .= "\tsend " . trim($option) . ";\n";
5526
		}
5527
	}
5528

    
5529
	$request_options = "";
5530
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5531
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5532
	}
5533

    
5534
	$required_options = "";
5535
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5536
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5537
	}
5538

    
5539
	$option_modifiers = "";
5540
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5541
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5542
		foreach ($modifiers as $modifier) {
5543
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5544
		}
5545
	}
5546

    
5547
	$dhclientconf  = "interface \"{$realif}\" {\n";
5548
	$dhclientconf .= "\n";
5549
	$dhclientconf .= "\tsupersede interface-mtu 0;\n";
5550
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5551
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5552
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5553
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5554
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5555
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5556
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5557
	$dhclientconf .= "\n";
5558
	$dhclientconf .= "# DHCP Protocol Options\n";
5559
	$dhclientconf .= "{$hostname}";
5560
	$dhclientconf .= "{$send_options}";
5561
	$dhclientconf .= "{$request_options}";
5562
	$dhclientconf .= "{$required_options}";
5563
	$dhclientconf .= "{$option_modifiers}";
5564
	$dhclientconf .= "\n";
5565
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5566
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5567
	}
5568
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5569
	$dhclientconf .= "}\n";
5570

    
5571
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5572

    
5573
	return $dhclientconf;
5574
}
5575

    
5576
function DHCP_Config_Option_Split($option_string) {
5577
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5578
	return $matches ? $matches[0] : [];
5579
}
5580

    
5581
function DHCP_Config_File_Override($ifcfg, $realif) {
5582

    
5583
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5584

    
5585
	if ($dhclientconf === false) {
5586
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5587
		return '';
5588
	} else {
5589
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5590
	}
5591
}
5592

    
5593

    
5594
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5595

    
5596
	/* Apply Interface Substitutions */
5597
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5598

    
5599
	/* Apply Hostname Substitutions */
5600
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5601

    
5602
	/* Arrays of MAC Address Types, Cases, Delimiters */
5603
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5604
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5605
	$various_mac_cases      = array("U", "L");
5606
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5607

    
5608
	/* Apply MAC Address Substitutions */
5609
	foreach ($various_mac_types as $various_mac_type) {
5610
		foreach ($various_mac_cases as $various_mac_case) {
5611
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5612

    
5613
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5614
				if ($res !== false) {
5615

    
5616
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5617
					if ("$various_mac_case" == "U") {
5618
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5619
					}
5620
					if ("$various_mac_case" == "L") {
5621
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5622
					}
5623

    
5624
					if ("$various_mac_type" == "mac_addr_hex") {
5625
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5626
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5627
						$dhcpclientconf_mac_hex = "";
5628
						$delimiter = "";
5629
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5630
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5631
							$delimiter = ":";
5632
						}
5633
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5634
					}
5635

    
5636
					/* MAC Address Delimiter Substitutions */
5637
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5638

    
5639
					/* Apply MAC Address Substitutions */
5640
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5641
				}
5642
			}
5643
		}
5644
	}
5645

    
5646
	return $dhclientconf;
5647
}
5648

    
5649
function interfaces_group_setup() {
5650
	global $config;
5651

    
5652
	if (!isset($config['ifgroups']['ifgroupentry']) ||
5653
	    !is_array($config['ifgroups']['ifgroupentry'])) {
5654
		return;
5655
	}
5656

    
5657
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5658
		interface_group_setup($groupar);
5659
	}
5660

    
5661
	return;
5662
}
5663

    
5664
function interface_group_setup(&$groupname /* The parameter is an array */) {
5665
	if (!is_array($groupname)) {
5666
		return;
5667
	}
5668
	$members = explode(" ", $groupname['members']);
5669
	foreach ($members as $ifs) {
5670
		$realif = get_real_interface($ifs);
5671
		if ($realif && does_interface_exist($realif)) {
5672
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5673
		}
5674
	}
5675

    
5676
	return;
5677
}
5678

    
5679
function is_interface_group($if) {
5680
	global $config;
5681

    
5682
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5683
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5684
			if ($groupentry['ifname'] === $if) {
5685
				return true;
5686
			}
5687
		}
5688
	}
5689

    
5690
	return false;
5691
}
5692

    
5693
function interface_group_add_member($interface, $groupname) {
5694
	$interface = get_real_interface($interface);
5695
	if (does_interface_exist($interface)) {
5696
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5697
	}
5698
}
5699

    
5700
/* COMPAT Function */
5701
function convert_friendly_interface_to_real_interface_name($interface) {
5702
	return get_real_interface($interface);
5703
}
5704

    
5705
/* COMPAT Function */
5706
function get_real_wan_interface($interface = "wan") {
5707
	return get_real_interface($interface);
5708
}
5709

    
5710
/* COMPAT Function */
5711
function get_current_wan_address($interface = "wan") {
5712
	return get_interface_ip($interface);
5713
}
5714

    
5715
/*
5716
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5717
 */
5718
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5719
	global $config;
5720

    
5721
	/* XXX: For speed reasons reference directly the interface array */
5722
	init_config_arr(array('interfaces'));
5723
	$ifdescrs = &$config['interfaces'];
5724
	//$ifdescrs = get_configured_interface_list(true);
5725

    
5726
	foreach ($ifdescrs as $if => $ifname) {
5727
		if ($if == $interface || $ifname['if'] == $interface) {
5728
			return $if;
5729
		}
5730

    
5731
		if (get_real_interface($if) == $interface) {
5732
			return $if;
5733
		}
5734

    
5735
		if ($checkparent == false) {
5736
			continue;
5737
		}
5738

    
5739
		$int = get_parent_interface($if, true);
5740
		if (is_array($int)) {
5741
			foreach ($int as $iface) {
5742
				if ($iface == $interface) {
5743
					return $if;
5744
				}
5745
			}
5746
		}
5747
	}
5748

    
5749
	if ($interface == "enc0") {
5750
		return 'IPsec';
5751
	}
5752
}
5753

    
5754
/* attempt to resolve interface to friendly descr */
5755
function convert_friendly_interface_to_friendly_descr($interface) {
5756
	global $config;
5757

    
5758
	$iface = config_get_path("interfaces/{$interface}");
5759
	switch ($interface) {
5760
		case "l2tp":
5761
			$ifdesc = "L2TP";
5762
			break;
5763
		case "pptp":
5764
			$ifdesc = "PPTP";
5765
			break;
5766
		case "pppoe":
5767
			$ifdesc = "PPPoE";
5768
			break;
5769
		case "openvpn":
5770
			$ifdesc = "OpenVPN";
5771
			break;
5772
		case "lo0":
5773
			$ifdesc = "Loopback";
5774
			break;
5775
		case "enc0":
5776
		case "ipsec":
5777
		case "IPsec":
5778
			$ifdesc = "IPsec";
5779
			break;
5780
		default:
5781
			if ($iface) {
5782
				if (empty($iface['descr'])) {
5783
					$ifdesc = strtoupper($interface);
5784
				} else {
5785
					$ifdesc = strtoupper($iface['descr']);
5786
				}
5787
				break;
5788
			} elseif (substr($interface, 0, 4) == '_vip') {
5789
				foreach (config_get_path('virtualip/vip', []) as $vip) {
5790
					if (($vip['mode'] == "carp") || ($vip['mode'] == "ipalias")) {
5791
						if ($interface == "_vip{$vip['uniqid']}") {
5792
							$descr = $vip['subnet'];
5793
							if (!empty($vip['vhid'])) {
5794
								$descr .= " (vhid {$vip['vhid']})";
5795
							}
5796
							if (!empty($vip['descr'])) {
5797
								$descr .= " - " .$vip['descr'];
5798
							}
5799
							return $descr;
5800
						}
5801
					}
5802
				}
5803
			} elseif (substr($interface, 0, 5) == '_lloc') {
5804
				return get_interface_linklocal($interface);
5805
			} else {
5806
				if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5807
					foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
5808
						if ($ifgen['ifname'] === $interface) {
5809
							return $ifgen['ifname'];
5810
						}
5811
					}
5812
				}
5813

    
5814
				/* if list */
5815
				$ifdescrs = get_configured_interface_with_descr(true);
5816
				foreach ($ifdescrs as $if => $ifname) {
5817
					if ($if == $interface || $ifname == $interface) {
5818
						return $ifname;
5819
					}
5820
				}
5821
			}
5822
			break;
5823
	}
5824

    
5825
	return $ifdesc;
5826
}
5827

    
5828
function convert_real_interface_to_friendly_descr($interface) {
5829

    
5830
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5831

    
5832
	if (!empty($ifdesc)) {
5833
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5834
	}
5835

    
5836
	return $interface;
5837
}
5838

    
5839
/*
5840
 *  get_parent_interface($interface):
5841
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5842
 *				or virtual interface (i.e. vlan)
5843
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5844
 *			-- returns $interface passed in if $interface parent is not found
5845
 *			-- returns empty array if an invalid interface is passed
5846
 *	(Only handles ppps and vlans now.)
5847
 */
5848
function get_parent_interface($interface, $avoidrecurse = false) {
5849
	$parents = array();
5850
	//Check that we got a valid interface passed
5851
	$realif = get_real_interface($interface);
5852
	if ($realif == NULL) {
5853
		return $parents;
5854
	}
5855

    
5856
	// If we got a real interface, find it's friendly assigned name
5857
	if ($interface == $realif && $avoidrecurse == false) {
5858
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5859
	}
5860

    
5861
	$iface = config_get_path("interfaces/{$interface}");
5862
	if (!empty($interface) && $iface) {
5863
		$ifcfg = $iface;
5864
		switch ($ifcfg['ipaddr']) {
5865
			case "ppp":
5866
			case "pppoe":
5867
			case "pptp":
5868
			case "l2tp":
5869
				if (empty($parents)) {
5870
					foreach (config_get_path('ppps/ppp') as $ppp) {
5871
						if ($ifcfg['if'] == $ppp['if']) {
5872
							$ports = explode(',', $ppp['ports']);
5873
							foreach ($ports as $pid => $parent_if) {
5874
								$parents[$pid] = get_real_interface($parent_if);
5875
							}
5876
							break;
5877
						}
5878
					}
5879
				}
5880
				break;
5881
			case "dhcp":
5882
			case "static":
5883
			default:
5884
				// Handle _vlans
5885
				$vlan = interface_is_vlan($ifcfg['if']);
5886
				if ($vlan != NULL) {
5887
					$parents[0] = $vlan['if'];
5888
				}
5889
				break;
5890
		}
5891
	}
5892

    
5893
	if (empty($parents)) {
5894
		// Handle _vlans not assigned to an interface
5895
		$vlan = interface_is_vlan($realif);
5896
		if ($vlan != NULL) {
5897
			$parents[0] = $vlan['if'];
5898
		}
5899
	}
5900

    
5901
	if (empty($parents)) {
5902
		/* Handle LAGGs. */
5903
		$lagg = interface_is_type($realif, 'lagg');
5904
		if ($lagg != NULL && isset($lagg['members'])) {
5905
			$parents = explode(",", $lagg['members']);
5906
		}
5907
	}
5908

    
5909
	if (empty($parents)) {
5910
		$parents[0] = $realif;
5911
	}
5912

    
5913
	return $parents;
5914
}
5915

    
5916
/*
5917
 *  get_parent_physical_interface($interface):
5918
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5919
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5920
 */
5921
function get_parent_physical_interface($interface) {
5922
	global $config;
5923

    
5924
	$realif = get_parent_interface($interface);
5925

    
5926
	if (substr($realif[0], 0, 4) == "lagg") {
5927
		foreach ($config['laggs']['lagg'] as $lagg) {
5928
			if ($realif[0] == $lagg['laggif']) {
5929
				return explode(",", $lagg['members']);
5930
			}
5931
		}
5932
	} else {
5933
		return $realif;
5934
	}
5935
}
5936

    
5937
function interface_is_wireless_clone($wlif) {
5938
	if (!stristr($wlif, "_wlan")) {
5939
		return false;
5940
	} else {
5941
		return true;
5942
	}
5943
}
5944

    
5945
function interface_get_wireless_base($wlif) {
5946
	if (!stristr($wlif, "_wlan")) {
5947
		return $wlif;
5948
	} else {
5949
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5950
	}
5951
}
5952

    
5953
function interface_get_wireless_clone($wlif) {
5954
	if (!stristr($wlif, "_wlan")) {
5955
		return $wlif . "_wlan0";
5956
	} else {
5957
		return $wlif;
5958
	}
5959
}
5960

    
5961
function interface_list_wireless() {
5962
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5963

    
5964
	$result = array();
5965
	foreach ($portlist as $port) {
5966
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5967
			continue;
5968
		}
5969

    
5970
		$desc = $port . " ( " . get_single_sysctl(
5971
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5972

    
5973
		$result[] = array(
5974
		    "if" => $port,
5975
		    "descr" => $desc
5976
		);
5977
	}
5978

    
5979
	return $result;
5980
}
5981

    
5982
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = false) {
5983
	global $g;
5984

    
5985
	$wanif = NULL;
5986

    
5987
	switch ($interface) {
5988
		case "l2tp":
5989
			$wanif = "l2tp";
5990
			break;
5991
		case "pptp":
5992
			$wanif = "pptp";
5993
			break;
5994
		case "pppoe":
5995
			$wanif = "pppoe";
5996
			break;
5997
		case "openvpn":
5998
			$wanif = "openvpn";
5999
			break;
6000
		case "IPsec":
6001
		case "ipsec":
6002
		case "enc0":
6003
			$wanif = "enc0";
6004
			break;
6005
		case "ppp":
6006
			$wanif = "ppp";
6007
			break;
6008
		default:
6009
			if (substr($interface, 0, 4) == '_vip') {
6010
				$wanif = get_configured_vip_interface($interface);
6011
				if (!empty($wanif)) {
6012
					$wanif = get_real_interface($wanif);
6013
				}
6014
				break;
6015
			} elseif (substr($interface, 0, 5) == '_lloc') {
6016
				$interface = substr($interface, 5);
6017
			} elseif (interface_is_vlan($interface) != NULL ||
6018
			    does_interface_exist($interface, $flush)) {
6019
				/*
6020
				 * If a real interface was already passed simply
6021
				 * pass the real interface back.  This encourages
6022
				 * the usage of this function in more cases so that
6023
				 * we can combine logic for more flexibility.
6024
				 */
6025
				$wanif = $interface;
6026
				break;
6027
			}
6028

    
6029
			$cfg = config_get_path("interfaces/{$interface}");
6030
			if (empty($cfg))
6031
				break;
6032

    
6033
			if ($family == "inet6") {
6034
				switch ($cfg['ipaddrv6']) {
6035
					case "6rd":
6036
					case "6to4":
6037
						$wanif = "{$interface}_stf";
6038
						break;
6039
					case 'pppoe':
6040
					case 'ppp':
6041
					case 'l2tp':
6042
					case 'pptp':
6043
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6044
							$wanif = interface_get_wireless_clone($cfg['if']);
6045
						} else {
6046
							$wanif = $cfg['if'];
6047
						}
6048
						break;
6049
					default:
6050
						switch ($cfg['ipaddr']) {
6051
							case 'pppoe':
6052
							case 'ppp':
6053
							case 'l2tp':
6054
							case 'pptp':
6055
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
6056
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) ||
6057
								    isset($cfg['ipv6usev4iface']) || isset($cfg['slaacusev4iface'])) {
6058
									$wanif = $cfg['if'];
6059
								} else {
6060
									$parents = get_parent_interface($interface);
6061
									if (!empty($parents[0])) {
6062
										$wanif = $parents[0];
6063
									} else {
6064
										$wanif = $cfg['if'];
6065
									}
6066
								}
6067
								break;
6068
							default:
6069
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6070
									$wanif = interface_get_wireless_clone($cfg['if']);
6071
								} else {
6072
									$wanif = $cfg['if'];
6073
								}
6074
								break;
6075
						}
6076
						break;
6077
				}
6078
			} else {
6079
				// Wireless cloned NIC support (FreeBSD 8+)
6080
				// interface name format: $parentnic_wlanparentnic#
6081
				// example: ath0_wlan0
6082
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6083
					$wanif = interface_get_wireless_clone($cfg['if']);
6084
				} else {
6085
					$wanif = $cfg['if'];
6086
				}
6087
			}
6088
			break;
6089
	}
6090

    
6091
	return $wanif;
6092
}
6093

    
6094
/* Guess the physical interface by providing a IP address */
6095
function guess_interface_from_ip($ipaddress) {
6096

    
6097
	if (!is_ipaddr($ipaddress)) {
6098
		return false;
6099
	}
6100

    
6101
	$route = route_get($ipaddress, '', true);
6102
	if (empty($route)) {
6103
		return false;
6104
	}
6105

    
6106
	if (!empty($route[0]['interface-name'])) {
6107
		return $route[0]['interface-name'];
6108
	}
6109

    
6110
	return false;
6111
}
6112

    
6113
/*
6114
 * find_ip_interface($ip): return the interface where an ip is defined
6115
 *   (or if $bits is specified, where an IP within the subnet is defined)
6116
 */
6117
function find_ip_interface($ip, $bits = null) {
6118
	if (!is_ipaddr($ip)) {
6119
		return false;
6120
	}
6121

    
6122
	$isv6ip = is_ipaddrv6($ip);
6123

    
6124
	/* if list */
6125
	$ifdescrs = get_configured_interface_list();
6126

    
6127
	foreach ($ifdescrs as $ifname) {
6128
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
6129
		if (is_null($ifip)) {
6130
			continue;
6131
		}
6132
		if (is_null($bits)) {
6133
			if ($ip == $ifip) {
6134
				$int = get_real_interface($ifname);
6135
				return $int;
6136
			}
6137
		} else {
6138
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
6139
				$int = get_real_interface($ifname);
6140
				return $int;
6141
			}
6142
		}
6143
	}
6144

    
6145
	return false;
6146
}
6147

    
6148
/*
6149
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
6150
 *   (or if $bits is specified, where an IP within the subnet is found)
6151
 */
6152
function find_virtual_ip_alias($ip, $bits = null) {
6153
	global $config;
6154

    
6155
	if (!is_array($config['virtualip']['vip'])) {
6156
		return false;
6157
	}
6158
	if (!is_ipaddr($ip)) {
6159
		return false;
6160
	}
6161

    
6162
	$isv6ip = is_ipaddrv6($ip);
6163

    
6164
	foreach ($config['virtualip']['vip'] as $vip) {
6165
		if ($vip['mode'] === "ipalias") {
6166
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
6167
				continue;
6168
			}
6169
			if (is_null($bits)) {
6170
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
6171
					return $vip;
6172
				}
6173
			} else {
6174
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
6175
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
6176
					return $vip;
6177
				}
6178
			}
6179
		}
6180
	}
6181
	return false;
6182
}
6183

    
6184
function link_interface_to_track6($int, $action = "") {
6185
	global $config;
6186

    
6187
	if (empty($int)) {
6188
		return;
6189
	}
6190

    
6191
	if (is_array($config['interfaces'])) {
6192
		$list = array();
6193
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
6194
			if (!isset($ifcfg['enable'])) {
6195
				continue;
6196
			}
6197
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
6198
				if ($action == "update") {
6199
					interface_track6_configure($ifname, $ifcfg);
6200
				} elseif ($action == "") {
6201
					$list[$ifname] = $ifcfg;
6202
				}
6203
			}
6204
		}
6205
		return $list;
6206
	}
6207
}
6208

    
6209
function interface_find_child_cfgmtu($realiface) {
6210
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
6211
	$vlans = link_interface_to_vlans($realiface);
6212
	$qinqs = link_interface_to_qinqs($realiface);
6213
	$bridge = link_interface_to_bridge($realiface);
6214
	$gifs = link_interface_to_tunnelif($interface, 'gif');
6215
	$gres = link_interface_to_tunnelif($interface, 'gre');
6216

    
6217
	$mtu = 0;
6218
	if (is_array($vlans)) {
6219
		foreach ($vlans as $vlan) {
6220
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
6221
			if (empty($ifass)) {
6222
				continue;
6223
			}
6224
			$vlanmtu = config_get_path("interfaces/{$ifass}/mtu");
6225
			if ($vlanmtu && (intval($vlanmtu) > $mtu)) {
6226
				$mtu = $vlanmtu;
6227
			}
6228
		}
6229
	}
6230
	if (is_array($qinqs)) {
6231
		foreach ($qinqs as $qinq) {
6232
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
6233
			if (empty($ifass)) {
6234
				continue;
6235
			}
6236

    
6237
			$qinqmtu = config_get_path("interfaces/{$ifass}/mtu");
6238
			if ($qinqmtu && (intval($qinqmtu) > $mtu)) {
6239
				$mtu = $qinqmtu;
6240
			}
6241
		}
6242
	}
6243
	foreach ($gifs as $gif) {
6244
		$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
6245
		if (empty($ifass)) {
6246
			continue;
6247
		}
6248

    
6249
		$gifmtu = config_get_path("interfaces/{$ifass}/mtu");
6250
		if ($gifmtu && (intval($gifmtu) > $mtu)) {
6251
			$mtu = $gifmtu;
6252
		}
6253
	}
6254
	foreach ($gres as $gre) {
6255
		$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
6256
		if (empty($ifass)) {
6257
			continue;
6258
		}
6259
		$gremtu = config_get_path("interfaces/{$ifass}/mtu");
6260
		if ($gremtu && (intval($gremtu) > $mtu)) {
6261
			$mtu = $gremtu;
6262
		}
6263
	}
6264
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
6265
	$ifassmtu = config_get_path("interfaces/{$ifass}/mtu");
6266
	if (!empty($ifass) && !empty($ifassmtu)) {
6267
		if ($ifassmtu > $mtu) {
6268
			$mtu = $ifassmtu;
6269
		}
6270
	}
6271
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
6272

    
6273
	return $mtu;
6274
}
6275

    
6276
function link_interface_to_vlans($int, $action = "") {
6277
	if (empty($int)) {
6278
		return;
6279
	}
6280

    
6281
	$ifaces = array();
6282
	foreach (config_get_path('vlans/vlan', []) as $vlan) {
6283
		if ($int == $vlan['if']) {
6284
			if ($action == "update") {
6285
				interfaces_bring_up($int);
6286
			} else {
6287
				$ifaces[$vlan['tag']] = $vlan;
6288
			}
6289
		}
6290
	}
6291
	if (!empty($ifaces)) {
6292
		return $ifaces;
6293
	}
6294
}
6295

    
6296
function link_interface_to_qinqs($int, $action = "") {
6297
	if (empty($int)) {
6298
		return;
6299
	}
6300

    
6301
	$ifaces = array();
6302
	foreach (config_get_path('qinqs/qinqentry', []) as $qinq) {
6303
		if ($int == $qinq['if']) {
6304
			if ($action == "update") {
6305
				interfaces_bring_up($int);
6306
			} else {
6307
				$ifaces[$qinq['tag']] = $qinq;
6308
			}
6309
		}
6310
	}
6311
	if (!empty($ifaces)) {
6312
		return $ifaces;
6313
	}
6314
}
6315

    
6316
function link_interface_to_vips($int, $action = "", $vhid = '') {
6317
	$updatevips = false;
6318

    
6319
	$result = array();
6320
	foreach (config_get_path('virtualip/vip', []) as $vip) {
6321
		if (substr($vip['interface'], 0, 4) == "_vip") {
6322
			$iface = get_configured_vip_interface($vip['interface']);
6323
		} else {
6324
			$iface = $vip['interface'];
6325
		}
6326
		if ($int != $iface) {
6327
			continue;
6328
		}
6329
		if ($action == "update") {
6330
			$updatevips = true;
6331
		} else {
6332
			if (empty($vhid) || ($vhid == $vip['vhid']) ||
6333
				substr($vip['interface'], 0, 4) == "_vip") {
6334
				$result[] = $vip;
6335
			}
6336
		}
6337
	}
6338
	if ($updatevips === true) {
6339
		interfaces_vips_configure($int);
6340
	}
6341
	return $result;
6342

    
6343
	return NULL;
6344
}
6345

    
6346
/****f* interfaces/link_interface_to_bridge
6347
 * NAME
6348
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6349
 * INPUTS
6350
 *   $ip
6351
 * RESULT
6352
 *   bridge[0-99]
6353
 ******/
6354
function link_interface_to_bridge($int) {
6355
	foreach (config_get_path('bridges/bridged', []) as $bridge) {
6356
		if (in_array($int, explode(',', $bridge['members']))) {
6357
			return "{$bridge['bridgeif']}";
6358
		}
6359
	}
6360
}
6361

    
6362
function link_interface_to_lagg($int) {
6363
	foreach (config_get_path('laggs/lagg', []) as $lagg) {
6364
		if (in_array($int, explode(',', $lagg['members']))) {
6365
			return "{$lagg['laggif']}";
6366
		}
6367
	}
6368
}
6369

    
6370
function link_interface_to_group($int) {
6371
	$result = array();
6372

    
6373
	foreach (config_get_path('ifgroups/ifgroupentry') as $group) {
6374
		if (in_array($int, explode(" ", $group['members']))) {
6375
			$result[$group['ifname']] = $int;
6376
		}
6377
	}
6378

    
6379
	return $result;
6380
}
6381

    
6382
function link_interface_to_tunnelif($interface, $type, $remote = 'any') {
6383
	$result = array();
6384

    
6385
	if (empty($interface)) {
6386
		return $result;
6387
	}
6388

    
6389
	if (!in_array($type, array('gre', 'gif'))) {
6390
		return $result;
6391
	}
6392

    
6393
	foreach (config_get_path("{$type}s/{$type}", []) as $tunnel) {
6394
		if (($tunnel['if'] == $interface) &&
6395
			(($remote == 'any') ||
6396
			 (is_ipaddrv4($tunnel['remote-addr']) && ($remote == 'inet')) ||
6397
			 (is_ipaddrv6($tunnel['remote-addr']) && ($remote == 'inet6')))) { 
6398
			$result[] = $tunnel;
6399
		}
6400
	}
6401

    
6402
	return $result;
6403
}
6404

    
6405
function link_interface_to_ppp_tunnelif($interface) {
6406
	$result = array();
6407

    
6408
	if (empty($interface)) {
6409
		return $result;
6410
	}
6411

    
6412
	init_config_arr(array('ppps', 'ppp'));
6413
	$realif = get_real_interface($interface);
6414
	foreach (config_get_path('ppps/ppp', []) as $ppp) {
6415
		if (($ppp['ports'] == $realif) && in_array($ppp['type'], array('l2tp', 'pptp'))) { 
6416
			$result[] = $ppp;
6417
		}
6418
	}
6419

    
6420
	return $result;
6421
}
6422

    
6423
/*
6424
 * find_interface_ip($interface): return the interface ip (first found)
6425
 */
6426
function find_interface_ip($interface, $flush = false) {
6427
	global $interface_ip_arr_cache;
6428
	global $interface_sn_arr_cache;
6429

    
6430
	$interface = str_replace("\n", "", $interface);
6431

    
6432
	if (!does_interface_exist($interface)) {
6433
		return;
6434
	}
6435

    
6436
	/* Setup IP cache */
6437
	if (!isset($interface_ip_arr_cache[$interface]) or $flush) {
6438
		if (file_exists("/var/db/${interface}_ip")) {
6439
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6440
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6441
			foreach ($ifaddrs as $ifaddr) {
6442
				list($ip, $mask) = explode("/", $ifaddr);
6443
				if ($ip == $ifip) {
6444
					$interface_ip_arr_cache[$interface] = $ip;
6445
					$interface_sn_arr_cache[$interface] = $mask;
6446
					break;
6447
				}
6448
			}
6449
		}
6450
		if (!isset($interface_ip_arr_cache[$interface])) {
6451
			$ifinfo = get_interface_addresses($interface);
6452
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6453
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6454
		}
6455
	}
6456

    
6457
	return $interface_ip_arr_cache[$interface];
6458
}
6459

    
6460
/*
6461
 * find_interface_ipv6($interface): return the interface ip (first found)
6462
 */
6463
function find_interface_ipv6($interface, $flush = false) {
6464
	global $interface_ipv6_arr_cache;
6465
	global $interface_snv6_arr_cache;
6466

    
6467
	$interface = trim($interface);
6468
	$interface = get_real_interface($interface);
6469

    
6470
	if (!does_interface_exist($interface)) {
6471
		return;
6472
	}
6473

    
6474
	/* Setup IP cache */
6475
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6476
		$ifinfo = get_interface_addresses($interface);
6477
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6478
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6479
	}
6480

    
6481
	return $interface_ipv6_arr_cache[$interface];
6482
}
6483

    
6484
/*
6485
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6486
 */
6487
function find_interface_ipv6_ll($interface, $flush = false) {
6488
	global $interface_llv6_arr_cache;
6489

    
6490
	$interface = str_replace("\n", "", $interface);
6491

    
6492
	if (!does_interface_exist($interface)) {
6493
		return;
6494
	}
6495

    
6496
	/* Setup IP cache */
6497
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6498
		$ifinfo = pfSense_getall_interface_addresses($interface);
6499
		foreach ($ifinfo as $line) {
6500
			if (strstr($line, ":")) {
6501
				$parts = explode("/", $line);
6502
				if (is_linklocal($parts[0])) {
6503
					$ifinfo['linklocal'] = $parts[0];
6504
				}
6505
			}
6506
		}
6507
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6508
	}
6509
	return $interface_llv6_arr_cache[$interface];
6510
}
6511

    
6512
function find_interface_subnet($interface, $flush = false) {
6513
	global $interface_sn_arr_cache;
6514
	global $interface_ip_arr_cache;
6515

    
6516
	$interface = str_replace("\n", "", $interface);
6517
	if (does_interface_exist($interface) == false) {
6518
		return;
6519
	}
6520

    
6521
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6522
		$ifinfo = get_interface_addresses($interface);
6523
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6524
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6525
	}
6526

    
6527
	return $interface_sn_arr_cache[$interface];
6528
}
6529

    
6530
function find_interface_subnetv6($interface, $flush = false) {
6531
	global $interface_snv6_arr_cache;
6532
	global $interface_ipv6_arr_cache;
6533

    
6534
	$interface = str_replace("\n", "", $interface);
6535
	if (does_interface_exist($interface) == false) {
6536
		return;
6537
	}
6538

    
6539
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6540
		$ifinfo = get_interface_addresses($interface);
6541
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6542
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6543
	}
6544

    
6545
	return $interface_snv6_arr_cache[$interface];
6546
}
6547

    
6548
function ip_in_interface_alias_subnet($interface, $ipalias) {
6549
	if (empty($interface) || !is_ipaddr($ipalias)) {
6550
		return false;
6551
	}
6552
	foreach (config_get_path('virtualip/vip',[]) as $vip) {
6553
		switch ($vip['mode']) {
6554
		case "ipalias":
6555
			if ($vip['interface'] <> $interface) {
6556
				break;
6557
			}
6558
			$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6559
			if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6560
				return true;
6561
			}
6562
			break;
6563
		}
6564
	}
6565

    
6566
	return false;
6567
}
6568

    
6569
function get_possible_listen_ips($include_ipv6_link_local=false) {
6570

    
6571
	$interfaces = get_configured_interface_with_descr();
6572
	foreach ($interfaces as $iface => $ifacename) {
6573
		if ($include_ipv6_link_local) {
6574
			/* This is to avoid going though added ll below */
6575
			if (substr($iface, 0, 5) == '_lloc') {
6576
				continue;
6577
			}
6578
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6579
			if (!empty($llip)) {
6580
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6581
			}
6582
		}
6583
	}
6584
	$viplist = get_configured_vip_list();
6585
	foreach ($viplist as $vip => $address) {
6586
		$interfaces[$vip] = $address;
6587
		if (get_vip_descr($address)) {
6588
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6589
		}
6590
	}
6591

    
6592
	$interfaces['lo0'] = 'Localhost';
6593

    
6594
	return $interfaces;
6595
}
6596

    
6597
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6598
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6599
	foreach (array('server', 'client') as $mode) {
6600
		foreach (config_get_path("openvpn/openvpn-{$mode}", []) as $setting) {
6601
			if (!isset($setting['disable'])) {
6602
				$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6603
				$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6604
			}
6605
		}
6606
	}
6607

    
6608
	init_config_arr(array('ipsec', 'phase1'));
6609
	foreach (config_get_path('ipsec/phase1') as $p1) {
6610
		if ($p1['disabled']) {
6611
			continue;
6612
		}
6613
		if (ipsec_vti($p1)) {
6614
			$vtiiflist = interface_ipsec_vti_list_p1($p1);
6615
			if (!empty($vtiiflist)) {
6616
				$sourceips = array_merge($sourceips, $vtiiflist);
6617
			}
6618
		}
6619
	}
6620
	return $sourceips;
6621
}
6622

    
6623
function get_interface_ip($interface = "wan", $gateways_status = false) {
6624
	if (substr($interface, 0, 4) == '_vip') {
6625
		return get_configured_vip_ipv4($interface);
6626
	} elseif (substr($interface, 0, 5) == '_lloc') {
6627
		/* No link-local address for v4. */
6628
		return null;
6629
	}
6630

    
6631
	$realif = get_failover_interface($interface, 'inet', $gateways_status);
6632
	if (!$realif) {
6633
		return null;
6634
	}
6635

    
6636
	if (substr($realif, 0, 4) == '_vip') {
6637
		return get_configured_vip_ipv4($realif);
6638
	} elseif (substr($realif, 0, 5) == '_lloc') {
6639
		/* No link-local address for v4. */
6640
		return null;
6641
	}
6642

    
6643
	$iface = config_get_path("interfaces/{$interface}");
6644
	if (is_array($iface) && is_ipaddr($iface['ipaddr'])) {
6645
		return ($iface['ipaddr']);
6646
	}
6647

    
6648
	/*
6649
	 * Beaware that find_interface_ip() is our last option, it will
6650
	 * return the first IP it find on interface, not necessarily the
6651
	 * main IP address.
6652
	 */
6653
	$curip = find_interface_ip($realif);
6654
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6655
		return $curip;
6656
	} else {
6657
		return null;
6658
	}
6659
}
6660

    
6661
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false, $gateways_status = false) {
6662
	if (substr($interface, 0, 4) == '_vip') {
6663
		return get_configured_vip_ipv6($interface);
6664
	} elseif (substr($interface, 0, 5) == '_lloc') {
6665
		return get_interface_linklocal($interface);
6666
	}
6667

    
6668
	$realif = get_failover_interface($interface, 'inet6', $gateways_status);
6669
	if (!$realif) {
6670
		return null;
6671
	}
6672

    
6673
	if (substr($realif, 0, 4) == '_vip') {
6674
		return get_configured_vip_ipv6($realif);
6675
	} elseif (substr($realif, 0, 5) == '_lloc') {
6676
		return get_interface_linklocal($realif);
6677
	}
6678

    
6679
	$iface = config_get_path("interfaces/{$interface}");
6680
	if (is_array($iface)) {
6681
		switch ($iface['ipaddr']) {
6682
			case 'pppoe':
6683
			case 'l2tp':
6684
			case 'pptp':
6685
			case 'ppp':
6686
				if (($iface['ipaddrv6'] == 'dhcp6') ||
6687
				    ($iface['ipaddrv6'] == 'slaac')) {
6688
					$realif = get_real_interface($interface, 'inet6', false);
6689
				}
6690
				break;
6691
		}
6692
		if (is_ipaddrv6($iface['ipaddrv6'])) {
6693
			return ($iface['ipaddrv6']);
6694
		}
6695
	}
6696

    
6697
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6698
	$checkif = is_array($iface) ? $interface : convert_real_interface_to_friendly_interface_name($interface);
6699
	if (config_get_path("interfaces/{$checkif}/ipaddrv6'", "") == 'track6') { 
6700
		$curip = get_interface_track6ip($checkif);
6701
		if ($curip) {
6702
			return $curip[0];
6703
		}
6704
	}
6705

    
6706
	/*
6707
	 * Beaware that find_interface_ip() is our last option, it will
6708
	 * return the first IP it find on interface, not necessarily the
6709
	 * main IP address.
6710
	 */
6711
	$curip = find_interface_ipv6($realif, $flush);
6712
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6713
		return $curip;
6714
	} else {
6715
		/*
6716
		 * NOTE: On the case when only the prefix is requested,
6717
		 * the communication on WAN will be done over link-local.
6718
		 */
6719
		$iface = config_get_path("interfaces/{$interface}");
6720
		if ($linklocal_fallback || (is_array($iface) && isset($iface['dhcp6prefixonly']))) {
6721
			$curip = find_interface_ipv6_ll($realif, $flush);
6722
			if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6723
				return $curip;
6724
			}
6725
		}
6726
	}
6727
	return null;
6728
}
6729

    
6730
function get_interface_linklocal($interface = "wan") {
6731

    
6732
	$realif = get_failover_interface($interface, 'inet6');
6733
	if (!$realif) {
6734
		return null;
6735
	}
6736

    
6737
	if (substr($interface, 0, 4) == '_vip') {
6738
		$realif = get_real_interface($interface);
6739
	} elseif (substr($interface, 0, 5) == '_lloc') {
6740
		$realif = get_real_interface(substr($interface, 5));
6741
	}
6742

    
6743
	$curip = find_interface_ipv6_ll($realif);
6744
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6745
		return $curip;
6746
	} else {
6747
		return null;
6748
	}
6749
}
6750

    
6751
function get_interface_track6ip($interface = "wan") {
6752
	$realif = get_real_interface($interface);
6753
	$vips = get_configured_vip_list('inet6');
6754

    
6755
	foreach (pfSense_getall_interface_addresses($realif) as $ifaddr) {
6756
		list($ip, $bits) = explode("/", $ifaddr);
6757
		$ip = text_to_compressed_ip6($ip);
6758
		if (is_ipaddrv6($ip) && !is_linklocal($ip)) {
6759
			if (is_array($vips) && !empty($vips)) {
6760
				foreach ($vips as $vip) {
6761
					if ($ip == text_to_compressed_ip6($vip)) {
6762
						continue 2;
6763
					}
6764
				}
6765
			}
6766
			return array($ip, $bits);
6767
		}
6768
	}
6769
	return false;
6770
}
6771

    
6772
function get_interface_subnet($interface = "wan") {
6773
	if (substr($interface, 0, 4) == '_vip') {
6774
		return (get_configured_vip_subnetv4($interface));
6775
	}
6776

    
6777
	$iface = config_get_path("interfaces/{$interface}");
6778
	if (is_array($iface) && !empty($iface['subnet']) && is_ipaddrv4($iface['ipaddr'])) {
6779
		return ($iface['subnet']);
6780
	}
6781

    
6782
	$realif = get_real_interface($interface);
6783
	if (!$realif) {
6784
		return (NULL);
6785
	}
6786

    
6787
	$cursn = find_interface_subnet($realif);
6788
	if (!empty($cursn)) {
6789
		return ($cursn);
6790
	}
6791

    
6792
	return (NULL);
6793
}
6794

    
6795
function get_interface_subnetv6($interface = "wan") {
6796
	if (substr($interface, 0, 4) == '_vip') {
6797
		return (get_configured_vip_subnetv6($interface));
6798
	} elseif (substr($interface, 0, 5) == '_lloc') {
6799
		$interface = substr($interface, 5);
6800
	}
6801

    
6802
	$iface = config_get_path("interfaces/{$interface}");
6803
	if (is_array($iface) && !empty($iface['subnetv6']) && is_ipaddrv6($iface['ipaddrv6'])) {
6804
		return ($iface['subnetv6']);
6805
	}
6806

    
6807
	$realif = get_real_interface($interface, 'inet6');
6808
	if (!$realif) {
6809
		return (NULL);
6810
	}
6811

    
6812
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6813
	if (config_get_path("interfaces/{$interface}/ipaddrv6") == 'track6') {
6814
		$curip = get_interface_track6ip($interface);
6815
		if ($curip) {
6816
			return $curip[1];
6817
		}
6818
	}
6819

    
6820
	$cursn = find_interface_subnetv6($realif);
6821
	if (!empty($cursn)) {
6822
		return ($cursn);
6823
	}
6824

    
6825
	return (NULL);
6826
}
6827

    
6828
/* return outside interfaces with a gateway */
6829
function get_interfaces_with_gateway() {
6830
	global $config;
6831

    
6832
	$ints = array();
6833

    
6834
	/* loop interfaces, check config for outbound */
6835
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6836
		switch ($ifname['ipaddr']) {
6837
			case "dhcp":
6838
			case "pppoe":
6839
			case "pptp":
6840
			case "l2tp":
6841
			case "ppp":
6842
				$ints[$ifdescr] = $ifdescr;
6843
				break;
6844
			default:
6845
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6846
				    !empty($ifname['gateway'])) {
6847
					$ints[$ifdescr] = $ifdescr;
6848
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6849
				    !empty($ifname['gateway'])) {
6850
					$ints[$ifdescr] = $ifdescr;
6851
				}
6852

    
6853
				break;
6854
		}
6855
	}
6856
	return $ints;
6857
}
6858

    
6859
/* return true if interface has a gateway */
6860
function interface_has_gateway($friendly) {
6861
	global $config;
6862

    
6863
	if (!empty($config['interfaces'][$friendly])) {
6864
		$ifname = &$config['interfaces'][$friendly];
6865
		switch ($ifname['ipaddr']) {
6866
			case "dhcp":
6867
				/* see https://redmine.pfsense.org/issues/5135 */
6868
				if (get_interface_gateway($friendly)) {
6869
					return true;
6870
				}
6871
				break;
6872
			case "pppoe":
6873
			case "pptp":
6874
			case "l2tp":
6875
			case "ppp":
6876
				return true;
6877
				break;
6878
			default:
6879
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6880
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6881
					return true;
6882
				}
6883
				$tunnelif = substr($ifname['if'], 0, 3);
6884
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6885
					if (find_interface_ip($ifname['if'])) {
6886
						return true;
6887
					}
6888
				}
6889
				if (!empty($ifname['gateway'])) {
6890
					return true;
6891
				}
6892
				break;
6893
		}
6894
	}
6895

    
6896
	return false;
6897
}
6898

    
6899
/* return true if interface has a gateway */
6900
function interface_has_gatewayv6($friendly) {
6901
	global $config;
6902

    
6903
	if (!empty($config['interfaces'][$friendly])) {
6904
		$ifname = &$config['interfaces'][$friendly];
6905
		switch ($ifname['ipaddrv6']) {
6906
			case "slaac":
6907
			case "dhcp6":
6908
			case "6to4":
6909
			case "6rd":
6910
				return true;
6911
				break;
6912
			default:
6913
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6914
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6915
					return true;
6916
				}
6917
				$tunnelif = substr($ifname['if'], 0, 3);
6918
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6919
					if (find_interface_ipv6($ifname['if'])) {
6920
						return true;
6921
					}
6922
				}
6923
				if (!empty($ifname['gatewayv6'])) {
6924
					return true;
6925
				}
6926
				break;
6927
		}
6928
	}
6929

    
6930
	return false;
6931
}
6932

    
6933
/****f* interfaces/is_altq_capable
6934
 * NAME
6935
 *   is_altq_capable - Test if interface is capable of using ALTQ
6936
 * INPUTS
6937
 *   $int            - string containing interface name
6938
 * RESULT
6939
 *   boolean         - true or false
6940
 ******/
6941

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

    
6957
	$int_family = remove_ifindex($int);
6958

    
6959
	if (in_array($int_family, $capable)) {
6960
		return true;
6961
	} elseif (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
6962
		return true;
6963
	} elseif (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
6964
		return true;
6965
	} elseif (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
6966
		return true;
6967
	} else {
6968
		return false;
6969
	}
6970
}
6971

    
6972
/****f* interfaces/is_interface_wireless
6973
 * NAME
6974
 *   is_interface_wireless - Returns if an interface is wireless
6975
 * RESULT
6976
 *   $tmp       - Returns if an interface is wireless
6977
 ******/
6978
function is_interface_wireless($interface) {
6979
	global $config, $g;
6980

    
6981
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
6982
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
6983
		if (preg_match($g['wireless_regex'], $interface)) {
6984
			if (isset($config['interfaces'][$friendly])) {
6985
				$config['interfaces'][$friendly]['wireless'] = array();
6986
			}
6987
			return true;
6988
		}
6989
		return false;
6990
	} else {
6991
		return true;
6992
	}
6993
}
6994

    
6995
function get_wireless_modes($interface) {
6996
	/* return wireless modes and channels */
6997
	$wireless_modes = array();
6998

    
6999
	$cloned_interface = get_real_interface($interface);
7000

    
7001
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7002
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
7003
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\n\" \$3 }'";
7004
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
7005

    
7006
		$interface_channels = "";
7007
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7008
		$interface_channel_count = count($interface_channels);
7009

    
7010
		$c = 0;
7011
		while ($c < $interface_channel_count) {
7012
			$channel_line = explode(",", $interface_channels["$c"]);
7013
			$wireless_mode = trim($channel_line[0]);
7014
			$wireless_channel = trim($channel_line[1]);
7015
			if (trim($wireless_mode) != "") {
7016
				/* if we only have 11g also set 11b channels */
7017
				if ($wireless_mode == "11g") {
7018
					if (!isset($wireless_modes["11b"])) {
7019
						$wireless_modes["11b"] = array();
7020
					}
7021
				} elseif ($wireless_mode == "11g ht") {
7022
					if (!isset($wireless_modes["11b"])) {
7023
						$wireless_modes["11b"] = array();
7024
					}
7025
					if (!isset($wireless_modes["11g"])) {
7026
						$wireless_modes["11g"] = array();
7027
					}
7028
					$wireless_mode = "11ng";
7029
				} elseif ($wireless_mode == "11a ht") {
7030
					if (!isset($wireless_modes["11a"])) {
7031
						$wireless_modes["11a"] = array();
7032
					}
7033
					$wireless_mode = "11na";
7034
				}
7035
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
7036
			}
7037
			$c++;
7038
		}
7039
	}
7040
	return($wireless_modes);
7041
}
7042

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

    
7048
		$interface_channels = "";
7049
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7050
		return $interface_channels;
7051
}
7052

    
7053
/* return wireless HT modes */
7054
function get_wireless_ht_modes($interface) {
7055
	$wireless_hts_supported = array(0 => gettext('Auto'));
7056

    
7057
	$cloned_interface = get_real_interface($interface);
7058

    
7059
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7060
		$interface_channels = get_wireless_channels($cloned_interface);
7061

    
7062
		foreach ($interface_channels as $channel) {
7063
			$channel_line = explode(",", $channel);
7064
			$wireless_ht = trim($channel_line[1]);
7065
			if (!empty($wireless_ht)) {
7066
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
7067
			}
7068
		}
7069
	}
7070
	return($wireless_hts_supported);
7071
}
7072

    
7073
/* return wireless HT by channel/standard */
7074
function get_wireless_ht_list($interface) {
7075
	$wireless_hts = array();
7076

    
7077
	$cloned_interface = get_real_interface($interface);
7078

    
7079
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7080
		$interface_channels = get_wireless_channels($cloned_interface);
7081
		$interface_channel_count = count($interface_channels);
7082

    
7083
		$c = 0;
7084
		while ($c < $interface_channel_count) {
7085
			$channel_line = explode(",", $interface_channels["$c"]);
7086
			$wireless_mode = trim($channel_line[0]);
7087
			$wireless_ht = trim($channel_line[1]);
7088
			$wireless_channel = trim($channel_line[2]);
7089
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
7090
				if ($wireless_mode == "11g") {
7091
					if (!isset($wireless_modes["11g"])) {
7092
						$wireless_hts["11g"] = array();
7093
					}
7094
					$wireless_mode = "11ng";
7095
				} elseif ($wireless_mode == "11a") {
7096
					if (!isset($wireless_modes["11a"])) {
7097
						$wireless_hts["11a"] = array();
7098
					}
7099
					$wireless_mode = "11na";
7100
				}
7101
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
7102
			}
7103
			$c++;
7104
		}
7105
	}
7106
	return($wireless_hts);
7107
}
7108

    
7109
/* return channel numbers, frequency, max txpower, and max regulation txpower */
7110
function get_wireless_channel_info($interface) {
7111
	$wireless_channels = array();
7112

    
7113
	$cloned_interface = get_real_interface($interface);
7114

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

    
7120
		$interface_channels = "";
7121
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7122

    
7123
		foreach ($interface_channels as $channel_line) {
7124
			$channel_line = explode(",", $channel_line);
7125
			if (!isset($wireless_channels[$channel_line[0]])) {
7126
				$wireless_channels[$channel_line[0]] = $channel_line;
7127
			}
7128
		}
7129
	}
7130
	return($wireless_channels);
7131
}
7132

    
7133
function set_interface_mtu($interface, $mtu) {
7134

    
7135
	/* LAGG interface must be destroyed and re-created to change MTU */
7136
	if ((substr($interface, 0, 4) == 'lagg') &&
7137
	    (!strstr($interface, "."))) {
7138
		if (isset($config['laggs']['lagg']) &&
7139
		    is_array($config['laggs']['lagg'])) {
7140
			foreach ($config['laggs']['lagg'] as $lagg) {
7141
				if ($lagg['laggif'] == $interface) {
7142
					interface_lagg_configure($lagg);
7143
					break;
7144
				}
7145
			}
7146
		}
7147
	} else {
7148
		pfSense_interface_mtu($interface, $mtu);
7149
		set_ipv6routes_mtu($interface, $mtu);
7150
	}
7151
}
7152

    
7153
/****f* interfaces/get_interface_mtu
7154
 * NAME
7155
 *   get_interface_mtu - Return the mtu of an interface
7156
 * RESULT
7157
 *   $tmp       - Returns the mtu of an interface
7158
 ******/
7159
function get_interface_mtu($interface) {
7160
	$mtu = pfSense_interface_getmtu($interface);
7161
	return $mtu['mtu'];
7162
}
7163

    
7164
function get_interface_mac($interface) {
7165
	$macinfo = get_interface_addresses($interface);
7166
	return $macinfo["macaddr"];
7167
}
7168

    
7169
function get_interface_vendor_mac($interface) {
7170
	global $g;
7171

    
7172
	$macinfo = get_interface_addresses($interface);
7173
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7174
	    "00:00:00:00:00:00") {
7175
		return ($macinfo["hwaddr"]);
7176
	}
7177

    
7178
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7179
	if (file_exists($hwaddr_file)) {
7180
		$macaddr = trim(file_get_contents($hwaddr_file));
7181
		if (is_macaddr($macaddr)) {
7182
			return ($macaddr);
7183
		}
7184
	} elseif (is_macaddr($macinfo['macaddr'])) {
7185
		/* Save original macaddress to be restored when necessary */
7186
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7187
	}
7188

    
7189
	return (NULL);
7190
}
7191

    
7192
/****f* pfsense-utils/generate_random_mac_address
7193
 * NAME
7194
 *   generate_random_mac - generates a random mac address
7195
 * INPUTS
7196
 *   none
7197
 * RESULT
7198
 *   $mac - a random mac address
7199
 ******/
7200
function generate_random_mac_address() {
7201
	$mac = "02";
7202
	for ($x = 0; $x < 5; $x++) {
7203
		$mac .= ":" . dechex(rand(16, 255));
7204
	}
7205
	return $mac;
7206
}
7207

    
7208
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7209
	global $g;
7210

    
7211
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7212

    
7213
	if (!empty($iface) && !empty($pppif)) {
7214
		$cron_cmd = <<<EOD
7215
#!/bin/sh
7216
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7217
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7218

    
7219
EOD;
7220

    
7221
		@file_put_contents($cron_file, $cron_cmd);
7222
		chmod($cron_file, 0755);
7223
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7224
	} else {
7225
		unlink_if_exists($cron_file);
7226
	}
7227
}
7228

    
7229
function get_interface_default_mtu($type = "ethernet") {
7230
	switch ($type) {
7231
		case "gre":
7232
			return 1476;
7233
			break;
7234
		case "gif":
7235
			return 1280;
7236
			break;
7237
		case "tun":
7238
		case "vlan":
7239
		case "tap":
7240
		case "ethernet":
7241
		default:
7242
			return 1500;
7243
			break;
7244
	}
7245

    
7246
	/* Never reached */
7247
	return 1500;
7248
}
7249

    
7250
function get_vip_descr($ipaddress) {
7251
	global $config;
7252

    
7253
	foreach ($config['virtualip']['vip'] as $vip) {
7254
		if ($vip['subnet'] == $ipaddress) {
7255
			return ($vip['descr']);
7256
		}
7257
	}
7258
	return "";
7259
}
7260

    
7261
function interfaces_staticarp_configure($if) {
7262
	if (config_get_path('system/developerspew')) {
7263
		$mt = microtime();
7264
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7265
	}
7266

    
7267
	$ifcfg = config_get_path("interfaces/{$if}");
7268

    
7269
	if (!$ifcfg['if'] || !$ifcfg['enable']) {
7270
		return 0;
7271
	}
7272

    
7273
	/* Enable staticarp, if enabled */
7274
	$staticarp = config_get_path("dhcpd/{$if}/staticarp");
7275
	if ($staticarp) {
7276
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7277
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7278
	} else {
7279
		/*
7280
		 * Interfaces do not have staticarp enabled by default
7281
		 * Let's not disable staticarp on freshly created interfaces
7282
		 */
7283
		if (!platform_booting()) {
7284
			mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7285
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7286
		}
7287
	}
7288

    
7289
	/* Enable static arp entries */
7290
	$staticmap = config_get_path("dhcpd/{$if}/staticmap", []);
7291
	if (is_array($staticmap)) {
7292
		foreach ($staticmap as $arpent) {
7293
			if (empty($arpent['ipaddr']) || empty($arpent['mac'])) {
7294
				continue;
7295
			}
7296
			if ($staticarp || isset($arpent['arp_table_static_entry'])) {
7297
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7298
			}
7299
		}
7300
	}
7301

    
7302
	return 0;
7303
}
7304

    
7305
function get_failover_interface($interface, $family = "all", $gateways_status = false) {
7306
	/* shortcut to get_real_interface if we find it in the config */
7307
	if (is_array(config_get_path("interfaces/{$interface}"))) {
7308
		return get_real_interface($interface, $family);
7309
	}
7310

    
7311
	/* compare against gateway groups */
7312
	$a_groups = return_gateway_groups_array(true, $gateways_status);
7313
	if (is_array($a_groups[$interface])) {
7314
		/* we found a gateway group, fetch the interface or vip */
7315
		if (!empty($a_groups[$interface][0]['vip'])) {
7316
			return $a_groups[$interface][0]['vip'];
7317
		} else {
7318
			return $a_groups[$interface][0]['int'];
7319
		}
7320
	}
7321
	/* fall through to get_real_interface */
7322
	/* XXX: Really needed? */
7323
	return get_real_interface($interface, $family);
7324
}
7325

    
7326
/****f* interfaces/interface_has_dhcp
7327
 * NAME
7328
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7329
 * INPUTS
7330
 *   interface or gateway group name
7331
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7332
 * RESULT
7333
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7334
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7335
 ******/
7336
function interface_has_dhcp($interface, $family = 4) {
7337
	$iface = config_get_path("interfaces/{$interface}");
7338
	if ($iface) {
7339
		if (($family == 4) && ($iface['ipaddr'] == "dhcp")) {
7340
			return true;
7341
		} elseif (($family == 6) && ($iface['ipaddrv6'] == "dhcp6")) {
7342
			return true;
7343
		} else {
7344
			return false;
7345
		}
7346
	}
7347

    
7348
	if ($family == 6) {
7349
		$dhcp_string = "_DHCP6";
7350
	} else {
7351
		$dhcp_string = "_DHCP";
7352
	}
7353

    
7354
	foreach (config_get_path('gateways/gateway_group', []) as $group) {
7355
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7356
			continue;
7357
		}
7358
		foreach ($group['item'] as $item) {
7359
			$item_data = explode("|", $item);
7360
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7361
				return true;
7362
			}
7363
		}
7364
	}
7365

    
7366
	return false;
7367
}
7368

    
7369
function remove_ifindex($ifname) {
7370
	return preg_replace("/[0-9]+$/", "", $ifname);
7371
}
7372

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

    
7376
	$viplist = get_configured_vip_list($family, $type);
7377
	foreach ($viplist as $vipid => $address) {
7378
		$interfaces[$vipid] = $address;
7379
		if ($type = VIP_CARP) {
7380
			$vip = get_configured_vip($vipid);
7381
			if (isset($vip) && is_array($vip) ) {
7382
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7383
			}
7384
		}
7385
		if (get_vip_descr($address)) {
7386
			$interfaces[$vipid] .= " (" . get_vip_descr($address) . ")";
7387
		}
7388
	}
7389
	return $interfaces;
7390
}
7391

    
7392
function return_gateway_groups_array_with_descr() {
7393
	$interfaces = array();
7394
	$grouplist = return_gateway_groups_array();
7395
	foreach (array_keys($grouplist) as $name) {
7396
		$interfaces[$name] = "GW Group {$name}";
7397
	}
7398
	return $interfaces;
7399
}
7400

    
7401
function get_serial_ports($short=false) {
7402
	$linklist = array();
7403
	if (!is_dir("/var/spool/lock")) {
7404
		mwexec("/bin/mkdir -p /var/spool/lock");
7405
	}
7406
	$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);
7407
	foreach ($serialports as $port) {
7408
		$port = trim($port);
7409
		$port = ($short) ? basename($port) : $port;
7410
		$linklist[$port] = $port;
7411
	}
7412
	return $linklist;
7413
}
7414

    
7415
function get_interface_ports() {
7416
	global $config;
7417
	$linklist = array();
7418
	$portlist = get_interface_list();
7419
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
7420
		foreach ($config['vlans']['vlan'] as $vlan) {
7421
			$portlist[$vlan['vlanif']] = $vlan;
7422
		}
7423
	}
7424

    
7425
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
7426
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
7427
			$members = explode(" ", $qinq['members']);
7428
			foreach ($members as $mem) {
7429
				$qentry = $qinq['vlanif'] . "." . $mem;
7430
				$portlist[$qentry] = $qentry;
7431
			}
7432
		}
7433
	}
7434

    
7435
	foreach ($portlist as $ifn => $ifinfo) {
7436
		$string = "";
7437
		if (is_array($ifinfo)) {
7438
			$string .= $ifn;
7439
			if ($ifinfo['mac']) {
7440
				$string .= " ({$ifinfo['mac']})";
7441
			}
7442
			if ($ifinfo['friendly']) {
7443
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7444
			} elseif ($ifinfo['descr']) {
7445
				$string .= " - {$ifinfo['descr']}";
7446
			}
7447
		} else {
7448
			$string .= $ifinfo;
7449
		}
7450

    
7451
		$linklist[$ifn] = $string;
7452
	}
7453
	return $linklist;
7454
}
7455

    
7456
function build_ppps_link_list() {
7457
	global $pconfig;
7458

    
7459
	$linklist = array('list' => array(), 'selected' => array());
7460

    
7461
	if ($pconfig['type'] == 'ppp') {
7462
		$linklist['list'] = get_serial_ports();
7463
	} else {
7464
		$iflist = get_interface_ports();
7465

    
7466
		$viplist = array();
7467
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7468
		foreach ($carplist as $vid => $vaddr) {
7469
			$vip = get_configured_vip($vid);
7470
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7471
		}
7472

    
7473
		$linklist['list'] = array_merge($iflist, $viplist);
7474

    
7475
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7476
		$lagglist = get_lagg_interface_list();
7477
		foreach ($lagglist as $lagg) {
7478
			/* LAGG members cannot be assigned */
7479
			$laggmembers = explode(',', $lagg['members']);
7480
			foreach ($laggmembers as $lagm) {
7481
				if (isset($linklist['list'][$lagm])) {
7482
					unset($linklist['list'][$lagm]);
7483
				}
7484
			}
7485
		}
7486
	}
7487

    
7488
	$selected_ports = array();
7489
	if (is_array($pconfig['interfaces'])) {
7490
		$selected_ports = $pconfig['interfaces'];
7491
	} elseif (!empty($pconfig['interfaces'])) {
7492
		$selected_ports = explode(',', $pconfig['interfaces']);
7493
	}
7494
	foreach ($selected_ports as $port) {
7495
		if (isset($linklist['list'][$port])) {
7496
			array_push($linklist['selected'], $port);
7497
		}
7498
	}
7499
	return($linklist);
7500
}
7501

    
7502
function create_interface_list($open = false) {
7503
	$iflist = array();
7504

    
7505
	// add group interfaces
7506
	config_get_path('ifgroups/ifgroupentry', []);
7507
	foreach (config_get_path('ifgroups/ifgroupentry', []) as $ifgen) {
7508
		if ($open || have_ruleint_access($ifgen['ifname'])) {
7509
			$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7510
		}
7511
	}
7512

    
7513
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7514
		if ($open || have_ruleint_access($ifent)) {
7515
			$iflist[$ifent] = $ifdesc;
7516
		}
7517
	}
7518

    
7519
	if (config_get_path('l2tp/mode', "") == "server" && ($open || have_ruleint_access("l2tp"))) {
7520
		$iflist['l2tp'] = gettext('L2TP VPN');
7521
	}
7522

    
7523
	if (is_pppoe_server_enabled() && ($open || have_ruleint_access("pppoe"))) {
7524
		$iflist['pppoe'] = gettext("PPPoE Server");
7525
	}
7526

    
7527
	// add ipsec interfaces
7528
	if (ipsec_enabled() && ($open || have_ruleint_access("enc0"))) {
7529
		$iflist["enc0"] = gettext("IPsec");
7530
	}
7531

    
7532
	// add openvpn/tun interfaces
7533
	if (config_get_path('openvpn/openvpn-server') || config_get_path('openvpn/openvpn-client')) {
7534
		$iflist["openvpn"] = gettext("OpenVPN");
7535
	}
7536

    
7537
	return($iflist);
7538
}
7539

    
7540
function is_pseudo_interface($inf, $tap=true) {
7541
	global $config;
7542
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7543
	foreach ($psifs as $pif) {
7544
		if (substr($inf, 0, strlen($pif)) == $pif) {
7545
			if (($pif == 'ovpn') && $tap) {
7546
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7547
				$type = ($m[1] == 'c') ? 'client' : 'server';
7548
				foreach ($config['openvpn']['openvpn-'.$type] as $ovpn) {
7549
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7550
						return false;
7551
					} elseif ($ovpn['vpnid'] == $m[2]) {
7552
						return true;
7553
					}
7554
				}
7555
			} else {
7556
				return true;
7557
			}
7558
		}
7559
	}
7560
	return false;
7561
}
7562

    
7563
function is_stf_interface($inf) {
7564
	global $config;
7565

    
7566
	if (is_array($config['interfaces'][$inf]) &&
7567
	    (($config['interfaces'][$inf]['ipaddrv6'] == '6rd') ||
7568
	    ($config['interfaces'][$inf]['ipaddrv6'] == '6to4'))) {
7569
	    return true;
7570
	}
7571

    
7572
	return false;
7573
}
7574

    
7575
function restart_interface_services($interface, $ipv6type = "") {
7576
	global $config;
7577

    
7578
	services_unbound_configure(true, $interface);
7579

    
7580
	services_igmpproxy_configure($interface);
7581
	services_snmpd_configure($interface);
7582
	vpn_l2tp_configure($interface);
7583

    
7584
	if (substr(config_get_path("interfaces/{$interface}/if",""), 0, 4) != "ovpn") {
7585
		openvpn_resync_all($interface);
7586
	}
7587
	ipsec_force_reload($interface);
7588

    
7589
	/* restart RADVD to announce correct IPv6 prefix
7590
	 * see https://redmine.pfsense.org/issues/12604 */ 
7591
	if ((($ipv6type == "staticv6") || ($ipv6type == "track6")) &&
7592
	    is_array($config['dhcpdv6'][$interface]) &&
7593
	    isset($config['dhcpdv6'][$interface]['ramode']) &&
7594
	    ($config['dhcpdv6'][$interface]['ramode'] != "disabled")) {
7595
		services_radvd_configure();
7596
	}
7597

    
7598
	if (config_path_enabled("dhcpd/{$interface}") ||
7599
	    config_path_enabled("dhcpdv6/{$interface}")) {
7600
		services_dhcpd_configure();
7601
	}
7602

    
7603
	init_config_arr(array('syslog'));
7604
	if (config_path_enabled('syslog') && ($interface == config_get_path('syslog/sourceip'))) {
7605
		system_syslogd_start();
7606
	}
7607
}
7608

    
7609
/**
7610
 * Return interface parameters and primary ipv4 and ipv6 addresses for the real iface
7611
 * $interface, identified by exclusion of VIPs. Deprecates pfSense_get_interface_addresses()
7612
 *
7613
 * Result array contains keyed values:
7614
 * - ipaddr: ipv4 address
7615
 * - subnetbits: ipv4 subnet bits
7616
 * - subnet: ipv4 subnet
7617
 * - broadcast: ipv4 broadcast addr (if applicable)
7618
 * - tunnel: ipv4 PPP endpoint (if applicable)
7619
 * - ipaddr6: ipv6 address
7620
 * - tentative: ipv6 tentative flag (if applicable)
7621
 * - subnetbits6: ipv6 subnet bits
7622
 * - tunnel6: ipv6 tunnel endpoint
7623
 * - status: up or down interface status
7624
 * - link0: per link layer defined flag
7625
 * - link1: per link layer defined flag
7626
 * - link2: per link layer defined flag
7627
 * - multicast: multicast support
7628
 * - loopback: interface is a loopback interface
7629
 * - pointtopoint: interface is point-to-point
7630
 * - promisc: interface in promisc mode
7631
 * - permanentpromisc: interface permanently in promisc mode
7632
 * - oactive: interface tx hardware queue is full
7633
 * - allmulti: interface receives all multicast packets
7634
 * - simplex: interface is simplex
7635
 * - linkstateup: interface link is up
7636
 * - iftype: wireless, ether, vlan, bridge, virtual, other
7637
 * - mtu: mtu of interface
7638
 * - caps: interface capabilities array
7639
 * - encaps: enabled capabilities array
7640
 * - macaddr: interface configured ethernet address
7641
 * - hwaddr: hardware ethernet address
7642
 */
7643
function get_interface_addresses($interface) {
7644
	$v4addrs = array();
7645
	$v6addrs = array();
7646
	$v4vips = array();
7647
	$v6vips = array();
7648
	$ifaddrs = pfSense_get_ifaddrs($interface);
7649

    
7650
	foreach (array_keys(get_configured_vip_list()) as $viface) {
7651
		$vip = get_configured_vip($viface);
7652
		if (is_ipaddrv4($vip['subnet'])) {
7653
			array_push($v4vips, $vip['subnet']);
7654
		} else if (is_ipaddrv6($vip['subnet'])) {
7655
			array_push($v6vips, $vip['subnet']);
7656
		}
7657
	}
7658

    
7659
	if ($ifaddrs['addrs']) {
7660
	   $v4addrs = array_filter($ifaddrs['addrs'], function($addr) use ($v4vips){
7661
		  return (array_search($addr['addr'], $v4vips) === false);
7662
	   });
7663
	}
7664

    
7665
	if ($ifaddrs['addrs6']) {
7666
	   $v6addrs = array_filter($ifaddrs['addrs6'], function($addr) use ($v6vips){
7667
		  return (array_search($addr['addr'], $v6vips) === false);
7668
	   });
7669
	}
7670
	/* Transform output to conform to pfSense_get_interface_addresses() */
7671
	if ($v4addrs) {
7672
		$v4addr = array_pop($v4addrs);
7673
		$ifaddrs['ipaddr'] = $v4addr['addr'];
7674
		foreach(array("subnetbits", "subnet", "broadcast", "tunnel") as $key) {
7675
			if (array_key_exists($key, $v4addr)) {
7676
				$ifaddrs[$key] = $v4addr[$key];
7677
			}
7678
		}
7679
	}
7680

    
7681
	if ($v6addrs) {
7682
		$v6addr = array_pop($v6addrs);
7683
		$ifaddrs['ipaddr6'] = $v6addr['addr'];
7684
		foreach(array("subnetbits", "tunnel") as $key) {
7685
			if (array_key_exists($key, $v6addr)) {
7686
				$ifaddrs[$key.'6'] = $v6addr[$key];
7687
			}
7688
		}
7689
		if (array_key_exists('tentative', $v6addr)) {
7690
			$ifaddrs['tentative'] = $v6addr['tentative'];
7691
		}
7692
	}
7693
	unset($ifaddrs['addrs']);
7694
	unset($ifaddrs['addrs6']);
7695

    
7696
	return($ifaddrs);
7697
}
7698
?>
(23-23/62)