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

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

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

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

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

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

    
61
	return true;
62
}
63

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

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

    
75
	return $interface_arr_cache;
76
}
77

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

    
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
	global $config;
103

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

    
108

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

    
124
	$ifacedata = pfSense_getall_interface_addresses($realif);
125

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

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

    
142
	return false;
143
}
144

    
145
function interfaces_loopback_configure() {
146
	global $g;
147

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

    
161
function vlan_valid_tag($tag = NULL) {
162

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

    
170
function qinq_inuse($qinq = NULL, $inqtag = NULL) {
171
        global $config;
172

    
173
	if ($qinq == NULL || $inqtag == NULL ||
174
	    !is_array($qinq) || !vlan_valid_tag($inqtag)) {
175
		return (false);
176
	}
177

    
178
        $iflist = get_configured_interface_list(true);
179
        foreach ($iflist as $if) {
180
                if ($config['interfaces'][$if]['if'] == qinq_interface($qinq, $inqtag)) {
181
                        return (true);
182
                }
183
        }
184

    
185
        return (false);
186
}
187

    
188
function qinq_interface($qinq = NULL, $inqtag = NULL) {
189

    
190
	if ($qinq == NULL || $inqtag == NULL || !is_array($qinq) ||
191
	    !isset($qinq['if']) || !isset($qinq['tag']) ||
192
	    !vlan_valid_tag($qinq['tag']) || !vlan_valid_tag($inqtag)) {
193
		return (NULL);
194
	}
195
	return ("{$qinq['if']}.{$qinq['tag']}.{$inqtag}");
196
}
197

    
198
function interface_is_qinq($if = NULL) {
199
	global $config;
200

    
201
	if ($if == NULL || empty($if) || !is_array($config['qinqs']['qinqentry'])) {
202
		return (NULL);
203
	}
204

    
205
	/* Check basic format. */
206
	list($qinqif, $vlantag, $inqtag) = explode(".", $if);
207
	if (empty($qinqif) || empty($vlantag) || empty($inqtag) ||
208
	    !vlan_valid_tag($vlantag) || !vlan_valid_tag($inqtag)) {
209
		return (NULL);
210
	}
211

    
212
	foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
213
		if ("{$qinqif}.{$vlantag}" != $qinq['vlanif']) {
214
			continue;
215
		}
216
		if (empty($qinq['members'])) {
217
			continue;
218
		}
219
		foreach (explode(" ", $qinq['members']) as $tag) {
220
			if ($if == qinq_interface($qinq, $tag)) {
221
				return ($qinq);
222
			}
223
		}
224
	}
225

    
226
	return (NULL);
227
}
228

    
229
function vlan_inuse($vlan) {
230
	global $config;
231

    
232
	if ($vlan == NULL || !is_array($vlan)) {
233
		return (false);
234
	}
235

    
236
	$iflist = get_configured_interface_list(true);
237
	foreach ($iflist as $if) {
238
		if ($config['interfaces'][$if]['if'] == $vlan['vlanif']) {
239
			return (true);
240
		}
241
	}
242

    
243
	return (false);
244
}
245

    
246
function interface_is_vlan($if = NULL) {
247
	global $config;
248

    
249
	if ($if == NULL || empty($if) || is_array($if)) {
250
		return (NULL);
251
	}
252

    
253
	/* Check basic format. */
254
	list($vlanif, $vlantag) = explode(".", $if);
255
	if (empty($vlanif) || empty($vlantag) || !vlan_valid_tag($vlantag)) {
256
		return (NULL);
257
	}
258

    
259
	/* Find the VLAN interface. */
260
	if (isset($config['vlans']['vlan']) && is_array($config['vlans']['vlan'])) {
261
		foreach ($config['vlans']['vlan'] as $vlanidx => $vlan) {
262
			if ($if == $vlan['vlanif']) {
263
				return ($vlan);
264
			}
265
		}
266
	}
267

    
268
	/* Check for the first level tag in QinQ interfaces. */
269
	if (isset($config['qinqs']['qinqentry']) && is_array($config['qinqs']['qinqentry'])) {
270
		foreach ($config['qinqs']['qinqentry'] as $qinqidx => $qinq) {
271
			if ($if == $qinq['vlanif']) {
272
				return ($qinq);
273
			}
274
		}
275
	}
276

    
277
	return (NULL);
278
}
279

    
280
function vlan_interface($vlan = NULL) {
281
	if ($vlan == NULL || !is_array($vlan) || !isset($vlan['if']) ||
282
	    !isset($vlan['tag']) || !vlan_valid_tag($vlan['tag'])) {
283
		return (NULL);
284
	}
285
	return ("{$vlan['if']}.{$vlan['tag']}");
286
}
287

    
288
function interface_set_macaddr($interface, $mac_addr) {
289
	if (empty($mac_addr) || !is_macaddr($mac_addr)) {
290
		return;
291
	}
292

    
293
	$current_mac = get_interface_mac($interface);
294

    
295
	/*
296
	 * Don't try to reapply the MAC if it's already applied.
297
	 * When ifconfig link is used, it cycles the interface down/up, which
298
	 * triggers the interface config again, which attempts to apply the
299
	 * MAC again, which cycles the link again...
300
	 */
301
	if ($mac_addr != $current_mac) {
302
		mwexec("/sbin/ifconfig " . escapeshellarg($interface) .
303
		    " link " . escapeshellarg($mac_addr));
304
	}
305
}
306

    
307
function interface_is_parent($if, $parent_check) {
308

    
309
	$parent_array = get_parent_interface($if);
310
	if (count($parent_array) > 1) {
311
		$parent = $parent_array;
312
	} else {
313
		$parent = $parent_array[0];
314
	}
315
	if (is_array($parent)) {
316
		foreach ($parent as $parentif) {
317
			if (strcasecmp($parent_check, $parentif) == 0) {
318
				return (TRUE);
319
			}
320
		}
321
	} else {
322
		$realif = get_real_interface($parent);
323
		if (strcasecmp($parent_check, $realif) == 0) {
324
			return (TRUE);
325
		}
326
	}
327
	return (FALSE);
328
}
329

    
330
function interface_has_clones($if) {
331
	global $config;
332

    
333
	/* Check LAGGs. */
334
	if (isset($config['laggs']) && isset($config['laggs']['lagg']) &&
335
	    is_array($config['laggs']['lagg'])) {
336
		foreach ($config['laggs']['lagg'] as $lagg) {
337
			if (interface_is_parent($lagg['laggif'], $if)) {
338
				return (TRUE);
339
			}
340
		}
341
	}
342
	/* Check VLANs. */
343
	if (isset($config['vlans']) && isset($config['vlans']['vlan']) &&
344
	    is_array($config['vlans']['vlan'])) {
345
		foreach ($config['vlans']['vlan'] as $vlan) {
346
			if (interface_is_parent($vlan['if'], $if)) {
347
				return (TRUE);
348
			}
349
		}
350
	}
351
	/* Check bridges. */
352
	if (isset($config['bridges']) && isset($config['bridges']['bridged']) &&
353
	    is_array($config['bridges']['bridged'])) {
354
		foreach ($config['bridges']['bridged'] as $bridge) {
355
			$members = explode(',', $bridge['members']);
356
			foreach ($members as $member) {
357
				if (interface_is_parent($member, $if)) {
358
					return (TRUE);
359
				}
360
			}
361
		}
362
	}
363

    
364
	return (FALSE);
365
}
366

    
367
function interfaces_vlan_configure($parentif = "") {
368
	global $config, $g;
369
	$dhcp6c_list = array();
370

    
371
	if (is_array($config['vlans']['vlan']) &&
372
	    count($config['vlans']['vlan'])) {
373
		if (platform_booting()) {
374
			echo gettext("Configuring VLAN interfaces...");
375
		}
376
		foreach ($config['vlans']['vlan'] as $vlan) {
377
			if (empty($vlan['vlanif'])) {
378
				$vlan['vlanif'] = vlan_interface($vlan);
379
			}
380
			if (!empty($parentif) && ($parentif != $vlan['if'])) {
381
				continue;
382
			}
383
			/* configure dhcp6 enabled VLAN interfaces later
384
			 * see https://redmine.pfsense.org/issues/3965 */
385
			$if = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
386
			if (!empty($config['interfaces'][$if]['ipaddrv6']) &&
387
			    $config['interfaces'][$if]['ipaddrv6'] == "dhcp6") {
388
				$dhcp6c_list[$if] = $vlan;
389
				continue;
390
			}
391

    
392
			/* XXX: Maybe we should report any errors?! */
393
			interface_vlan_configure($vlan, false);
394
		}
395
		foreach ($dhcp6c_list as $if => $vlan) {
396
			interface_vlan_configure($vlan, false);
397
		}
398
		/* Invalidate cache */
399
		get_interface_arr(true);
400
		if (platform_booting()) {
401
			echo gettext("done.") . "\n";
402
		}
403
	}
404
}
405

    
406
function interface_vlan_configure(&$vlan, $flush = true) {
407
	global $config, $g;
408

    
409
	if (!is_array($vlan)) {
410
		log_error(gettext("VLAN: called with wrong options. Problems with config!"));
411
		return(NULL);
412
	}
413
	$if = $vlan['if'];
414
	if (empty($if)) {
415
		log_error(gettext("interface_vlan_configure called with if undefined."));
416
		return(NULL);
417
	}
418

    
419
	$vlanif = empty($vlan['vlanif']) ? vlan_interface($vlan) : $vlan['vlanif'];
420
	if ($vlanif == NULL) {
421
		log_error(gettext("vlan_interface called with if undefined var."));
422
		return(NULL);
423
	}
424
	$tag = $vlan['tag'];
425
	$pcp  = empty($vlan['pcp']) ? 0 : $vlan['pcp'];	/* Apply "Best Effort" if not set */
426

    
427
	/* make sure the parent interface is up */
428
	interfaces_bring_up($if);
429
	/* Since we are going to add vlan(4) try to enable all that hardware supports. */
430
	pfSense_interface_capabilities($if, IFCAP_VLAN_HWTAGGING|IFCAP_VLAN_MTU|IFCAP_VLAN_HWFILTER);
431

    
432
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
433
		pfSense_interface_destroy($vlanif);
434
	}
435

    
436
	$tmpvlanif = pfSense_interface_create2("vlan");
437
	pfSense_interface_rename($tmpvlanif, $vlanif);
438
	pfSense_ngctl_name("{$tmpvlanif}:", $vlanif);
439

    
440
	pfSense_vlan_create($vlanif, $if, $tag, $pcp);
441

    
442
	interfaces_bring_up($vlanif);
443

    
444
	/* invalidate interface cache */
445
	if ($flush) {
446
		get_interface_arr(true);
447
	}
448

    
449
	/* configure interface if assigned */
450
	$assignedif = convert_real_interface_to_friendly_interface_name($vlanif);
451
	if ($assignedif) {
452
		if (isset($config['interfaces'][$assignedif]['enable'])) {
453
			interface_configure($assignedif, true);
454
		}
455
	}
456

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

    
460
	if (interface_vlan_mtu_configured($vlanif)) {
461
		set_interface_mtu($vlanif, interface_vlan_mtu_configured($vlanif));
462
	}
463

    
464
	return $vlanif;
465
}
466

    
467
/*
468
 * reconfigure VLAN childs interfaces after MTU changes, see
469
 * https://redmine.pfsense.org/issues/11035
470
 */
471
function interfaces_vlan_configure_mtu($parentif = "") {
472
	global $config;
473

    
474
	init_config_arr(array('ppps', 'ppp'));
475
	if (!is_array($config['vlans']['vlan']) ||
476
	    !count($config['vlans']['vlan'])) {
477
		return;
478
	}
479

    
480
	foreach ($config['vlans']['vlan'] as $vlan) {
481
		if ($parentif != $vlan['if']) {
482
			continue;
483
		}
484
		if (interface_vlan_mtu_configured($vlan['vlanif'])) {
485
		       set_interface_mtu($vlan['vlanif'],
486
			   interface_vlan_mtu_configured($vlan['vlanif']));
487
		}
488
		if (empty($config['ppps']['ppp'])) {
489
			continue;
490
		}
491
		// PPP interfaces must be restarted to adjust MTU changes
492
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
493
			$ports = explode(',', $ppp['ports']);
494
			foreach ($ports as $pid => $port) {
495
				if ($port != $vlan['vlanif']) {
496
					continue;
497
				}
498
				$confif = convert_real_interface_to_friendly_interface_name($ppp['if']);
499
				interface_configure($confif);
500
			}
501
		}
502
	}
503
}
504

    
505
function interface_qinq_configure(&$qinq, $fd = NULL, $flush = true) {
506
	global $config, $g;
507

    
508
	if (!is_array($qinq)) {
509
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
510
		return;
511
	}
512

    
513
	$qinqif = $qinq['if'];
514
	$tag = $qinq['tag'];
515
	if (empty($qinqif)) {
516
		log_error(sprintf(gettext("interface_qinq_configure called with if undefined.%s"), "\n"));
517
		return;
518
	}
519

    
520
	if (!does_interface_exist($qinqif)) {
521
		log_error(sprintf(gettext("interface_qinq_configure called with invalid if.%s"), "\n"));
522
		return;
523
	}
524

    
525
	$vlanif = interface_vlan_configure($qinq);
526
	if ($vlanif == NULL || $vlanif != $qinq['vlanif']) {
527
		log_error(gettext("interface_qinq_configure cannot create VLAN interface"));
528
		return;
529
	}
530

    
531
	if ($fd == NULL) {
532
		$exec = true;
533
		$fd = fopen("{$g['tmp_path']}/netgraphcmd", "w");
534
	} else {
535
		$exec = false;
536
	}
537
	/* make sure the parent is converted to ng_vlan(4) and is up */
538
	interfaces_bring_up($qinqif);
539

    
540
	$ngif = str_replace(".", "_", $vlanif);
541
	if (!empty($vlanif) && does_interface_exist($vlanif)) {
542
		exec("/usr/sbin/ngctl shutdown {$ngif}qinq: > /dev/null 2>&1");
543
		exec("/usr/sbin/ngctl msg {$ngif}qinq: gettable > /dev/null 2>&1", $result);
544
		if (empty($result)) {
545
			fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
546
			fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
547
			fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
548
		}
549
	} else {
550
		fwrite($fd, "mkpeer {$ngif}: vlan lower downstream\n");
551
		fwrite($fd, "name {$ngif}:lower {$ngif}qinq\n");
552
		fwrite($fd, "connect {$ngif}: {$ngif}qinq: upper nomatch\n");
553
	}
554

    
555
	/* invalidate interface cache */
556
	if ($flush) {
557
		get_interface_arr(true);
558
	}
559

    
560
	if (interface_is_vlan($qinqif) == NULL) {
561
		mwexec("/sbin/ifconfig {$qinqif} promisc\n");
562
	}
563

    
564
	$macaddr = get_interface_mac($qinqif);
565
	if (!empty($qinq['members'])) {
566
		$qinqcmdbuf = "";
567
		$members = explode(" ", $qinq['members']);
568
		foreach ($members as $qtag) {
569
			$qinq2 = array();
570
			$qinq2['tag'] = $qtag;
571
			$qinq2['if'] = $vlanif;
572
			interface_qinq2_configure($qinq2, $qinqcmdbuf, $macaddr,
573
			    false);
574
			unset($qinq2);
575
		}
576
		if (strlen($qinqcmdbuf) > 0) {
577
			fwrite($fd, $qinqcmdbuf);
578
		}
579
	}
580
	if ($exec == true) {
581
		fclose($fd);
582
		mwexec("/usr/sbin/ngctl -f {$g['tmp_path']}/netgraphcmd > /dev/null 2>&1");
583
	}
584

    
585
	interfaces_bring_up($qinqif);
586
	if (!empty($qinq['members'])) {
587
		$members = explode(" ", $qinq['members']);
588
		foreach ($members as $qtag) {
589
			interfaces_bring_up(qinq_interface($qinq, $qtag));
590
		}
591
	}
592

    
593
	return $vlanif;
594
}
595

    
596
function interfaces_qinq_configure($ovpn=false) {
597
	global $config, $g;
598

    
599
	if (is_array($config['qinqs']['qinqentry']) &&
600
	    count($config['qinqs']['qinqentry'])) {
601
		if (platform_booting() && $ovpn) {
602
			echo gettext("Configuring OpenVPN QinQ interfaces...");
603
		} elseif (platform_booting()) {
604
			echo gettext("Configuring QinQ interfaces...");
605
		}
606
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
607
			if (($ovpn && strstr($qinq['if'], "ovpn")) ||
608
			    (!$ovpn && !strstr($qinq['if'], "ovpn"))) {
609
				interface_qinq_configure($qinq, NULL, false);
610
			}
611
		}
612
		/* Invalidate cache */
613
		get_interface_arr(true);
614
		if (platform_booting()) {
615
			echo gettext("done.") . "\n";
616
		}
617
	}
618
}
619

    
620
function interface_qinq2_configure(&$qinq, &$cmdbuf, $macaddr, $flush = true) {
621
	global $config, $g;
622

    
623
	if (!is_array($qinq)) {
624
		log_error(sprintf(gettext("QinQ compat VLAN: called with wrong options. Problems with config!%s"), "\n"));
625
		return;
626
	}
627

    
628
	$if = $qinq['if'];
629
	if (empty($if)) {
630
		log_error(sprintf(gettext("interface_qinq2_configure called with if undefined.%s"), "\n"));
631
		return;
632
	}
633
	$tag = $qinq['tag'];
634
	$vlanif = "{$if}.{$tag}";
635
	$ngif = str_replace(".", "_", $if);
636
	if (strlen($vlanif) > IF_NAMESIZE) {
637
		log_error(sprintf(gettext("interface_qinq2_configure interface name too big %s. (max. size: %d).%s"),
638
		    $vlanif, IF_NAMESIZE, "\n"));
639
		return;
640
	}
641

    
642
	exec("/usr/sbin/ngctl shutdown {$ngif}h{$tag}: > /dev/null 2>&1");
643
	$cmdbuf .= "mkpeer {$ngif}qinq: eiface {$ngif}{$tag} ether\n";
644
	$cmdbuf .= "name {$ngif}qinq:{$ngif}{$tag} {$ngif}h{$tag}\n";
645
	$cmdbuf .= "msg {$ngif}qinq: addfilter { vlan={$tag} hook=\"{$ngif}{$tag}\" }\n";
646
	$cmdbuf .= "msg {$ngif}h{$tag}: setifname \"{$vlanif}\"\n";
647
	$cmdbuf .= "msg {$ngif}h{$tag}: set {$macaddr}\n";
648

    
649
	/* invalidate interface cache */
650
	if ($flush) {
651
		get_interface_arr(true);
652
	}
653

    
654
	return $vlanif;
655
}
656

    
657
function interfaces_create_wireless_clones() {
658
	global $config, $g;
659

    
660
	$iflist = get_configured_interface_list();
661

    
662
	foreach ($iflist as $if) {
663
		$realif = $config['interfaces'][$if]['if'];
664
		if (!is_interface_wireless($realif)) {
665
			continue;
666
		}
667
		interface_wireless_clone(interface_get_wireless_clone($realif),
668
		    $config['interfaces'][$if]);
669
	}
670

    
671
	if (isset($config['wireless']['clone']) &&
672
	    is_array($config['wireless']['clone']) &&
673
	    count($config['wireless']['clone'])) {
674
		if (platform_booting()) {
675
			echo gettext("Creating wireless clone interfaces...");
676
		}
677
		/* Invalidate cache */
678
		get_interface_arr(true);
679
		foreach ($config['wireless']['clone'] as $clone) {
680
			if (empty($clone['cloneif'])) {
681
				continue;
682
			}
683
			if (does_interface_exist($clone['cloneif'])) {
684
				continue;
685
			}
686
			/* XXX: Maybe we should report any errors?! */
687
			interface_wireless_clone($clone['cloneif'], $clone);
688
		}
689
		if (platform_booting()) {
690
			echo gettext("done.") . "\n";
691
		}
692
	}
693
}
694

    
695
function interfaces_bridge_configure($checkmember = 0, $realif = "") {
696
	global $config;
697

    
698
	if (!isset($config['bridges']['bridged']) ||
699
	    !is_array($config['bridges']['bridged']) ||
700
	    !count($config['bridges']['bridged'])) {
701
		return;
702
	}
703

    
704
	$i = 0;
705
	foreach ($config['bridges']['bridged'] as $bridge) {
706
		if (empty($bridge['bridgeif'])) {
707
			$bridge['bridgeif'] = "bridge{$i}";
708
		}
709
		if (!empty($realif) && ($realif != $bridge['bridgeif'])) {
710
			continue;
711
		}
712
		$ifname = false;
713
		foreach ($config['interfaces'] as $intname => $intpar) {
714
			if ($intpar['if'] == $bridge['bridgeif']) {
715
				$ifname = $intname;
716
				break;
717
			}
718
		}
719

    
720
		if ($ifname && ($config['interfaces'][$ifname]['ipaddrv6'] == "track6")) {
721
			if ($checkmember == 1) {
722
				continue;
723
			} else {
724
				$checkmember = 0;
725
			}
726
		} elseif (($checkmember == 2) && !$ifname) {
727
			continue;
728
		}
729

    
730
		/* XXX: Maybe we should report any errors?! */
731
		interface_bridge_configure($bridge, $checkmember, false);
732
		$i++;
733
	}
734

    
735
	/* Invalidate cache */
736
	get_interface_arr(true);
737
}
738

    
739
function interface_bridge_configure(&$bridge, $checkmember = 0, $flush = true) {
740
	global $config, $g;
741

    
742
	if (!is_array($bridge)) {
743
		return;
744
	}
745

    
746
	if (empty($bridge['members'])) {
747
		log_error(sprintf(gettext("No members found on %s"), $bridge['bridgeif']));
748
		return;
749
	}
750

    
751
	$members = explode(',', $bridge['members']);
752
	if (!count($members)) {
753
		return;
754
	}
755

    
756
	/* Calculate smaller mtu and enforce it */
757
	$smallermtu = 0;
758
	$foundgif = false;
759
	foreach ($members as $member) {
760
		$realif = get_real_interface($member);
761
		$mtu = get_interface_mtu($realif);
762
		if (substr($realif, 0, 3) == "gif") {
763
			$foundgif = true;
764
			if ($checkmember == 1) {
765
				return;
766
			}
767
			if ($mtu <= 1500) {
768
				continue;
769
			}
770
		}
771
		if ($smallermtu == 0 && !empty($mtu)) {
772
			$smallermtu = $mtu;
773
		} elseif (!empty($mtu) && $mtu < $smallermtu) {
774
			$smallermtu = $mtu;
775
		}
776
	}
777
	if ($foundgif == false && $checkmember == 2) {
778
		return;
779
	}
780

    
781
	/* Just in case anything is not working well */
782
	if ($smallermtu == 0) {
783
		$smallermtu = 1500;
784
	}
785

    
786
	if (!empty($bridge['bridgeif'])) {
787
		pfSense_interface_destroy($bridge['bridgeif']);
788
		pfSense_interface_create2($bridge['bridgeif']);
789
		$bridgeif = escapeshellarg($bridge['bridgeif']);
790
	} else {
791
		// if called directly, as interfaces_bridge_edit.php does, and bridgeif isn't set
792
		// normally set by interfaces_bridge_configure, but not upon creation of new bridge
793
		$bridgeif = pfSense_interface_create2("bridge");
794
		$bridge['bridgeif'] = $bridgeif;
795
	}
796

    
797
	$bridgemtu = interface_find_child_cfgmtu($bridge['bridgeif']);
798
	if ($bridgemtu > $smallermtu) {
799
		$smallermtu = $bridgemtu;
800
	}
801

    
802
	$checklist = get_configured_interface_list();
803

    
804
	/* Add interfaces to bridge */
805
	foreach ($members as $member) {
806
		if (empty($checklist[$member])) {
807
			continue;
808
		}
809
		$realif = get_real_interface($member);
810
		if (!$realif) {
811
			log_error(gettext("realif not defined in interfaces bridge - up"));
812
			continue;
813
		}
814
		/* make sure the parent interface is up */
815
		pfSense_interface_mtu($realif, $smallermtu);
816
		interfaces_bring_up($realif);
817
		enable_hardware_offloading($member);
818
		pfSense_bridge_add_member($bridge['bridgeif'], $realif);
819
	}
820

    
821
	if (isset($bridge['enablestp'])) {
822
		interface_bridge_configure_stp($bridge);
823
	}
824

    
825
	interface_bridge_configure_advanced($bridge);
826

    
827
	interface_bridge_configure_ip6linklocal($bridge);
828

    
829
	if ($flush) {
830
		get_interface_arr(true);
831
	}
832

    
833
	if ($bridge['bridgeif']) {
834
		interfaces_bring_up($bridge['bridgeif']);
835
	} else {
836
		log_error(gettext("bridgeif not defined -- could not bring interface up"));
837
	}
838
}
839

    
840
function interface_bridge_configure_stp($bridge) {
841
	if (isset($bridge['enablestp'])) {
842
		$bridgeif = trim($bridge['bridgeif']);
843
		/* configure spanning tree proto */
844
		mwexec("/sbin/ifconfig {$bridgeif} proto " . escapeshellarg($bridge['proto']));
845

    
846
		if (!empty($bridge['stp'])) {
847
			$stpifs = explode(',', $bridge['stp']);
848
			foreach ($stpifs as $stpif) {
849
				$realif = get_real_interface($stpif);
850
				mwexec("/sbin/ifconfig {$bridgeif} stp {$realif}");
851
			}
852
		}
853
		if (!empty($bridge['maxage'])) {
854
			mwexec("/sbin/ifconfig {$bridgeif} maxage " . escapeshellarg($bridge['maxage']));
855
		}
856
		if (!empty($bridge['fwdelay'])) {
857
			mwexec("/sbin/ifconfig {$bridgeif} fwddelay " . escapeshellarg($bridge['fwdelay']));
858
		}
859
		if (!empty($bridge['hellotime'])) {
860
			mwexec("/sbin/ifconfig {$bridgeif} hellotime " . escapeshellarg($bridge['hellotime']));
861
		}
862
		if (!empty($bridge['priority'])) {
863
			mwexec("/sbin/ifconfig {$bridgeif} priority " . escapeshellarg($bridge['priority']));
864
		}
865
		if (!empty($bridge['holdcnt'])) {
866
			mwexec("/sbin/ifconfig {$bridgeif} holdcnt " . escapeshellarg($bridge['holdcnt']));
867
		}
868
		if (!empty($bridge['ifpriority'])) {
869
			$pconfig = explode(",", $bridge['ifpriority']);
870
			$ifpriority = array();
871
			foreach ($pconfig as $cfg) {
872
				$embcfg = explode_assoc(":", $cfg);
873
				foreach ($embcfg as $key => $value) {
874
					$ifpriority[$key] = $value;
875
				}
876
			}
877
			foreach ($ifpriority as $key => $value) {
878
				$realif = get_real_interface($key);
879
				mwexec("/sbin/ifconfig ${bridgeif} ifpriority {$realif} " . escapeshellarg($value));
880
			}
881
		}
882
		if (!empty($bridge['ifpathcost'])) {
883
			$pconfig = explode(",", $bridge['ifpathcost']);
884
			$ifpathcost = array();
885
			foreach ($pconfig as $cfg) {
886
				$embcfg = explode_assoc(":", $cfg);
887
				foreach ($embcfg as $key => $value) {
888
					$ifpathcost[$key] = $value;
889
				}
890
			}
891
			foreach ($ifpathcost as $key => $value) {
892
				$realif = get_real_interface($key);
893
				mwexec("/sbin/ifconfig ${bridgeif} ifpathcost {$realif} " . escapeshellarg($value));
894
			}
895
		}
896
	}
897
}
898

    
899
function interface_bridge_configure_advanced($bridge) {
900
	$bridgeif = trim($bridge['bridgeif']);
901

    
902
	if ($bridge['maxaddr'] <> "") {
903
		mwexec("/sbin/ifconfig {$bridgeif} maxaddr " . escapeshellarg($bridge['maxaddr']));
904
	}
905
	if ($bridge['timeout'] <> "") {
906
		mwexec("/sbin/ifconfig {$bridgeif} timeout " . escapeshellarg($bridge['timeout']));
907
	}
908
	if (!empty($bridge['span'])) {
909
		$spanifs = explode(",", $bridge['span']);
910
		foreach ($spanifs as $spanif) {
911
			$realif = get_real_interface($spanif);
912
			mwexec("/sbin/ifconfig {$bridgeif} span {$realif}");
913
		}
914
	}
915
	if (!empty($bridge['edge'])) {
916
		$edgeifs = explode(',', $bridge['edge']);
917
		foreach ($edgeifs as $edgeif) {
918
			$realif = get_real_interface($edgeif);
919
			mwexec("/sbin/ifconfig {$bridgeif} edge {$realif}");
920
		}
921
	}
922
	if (!empty($bridge['autoedge'])) {
923
		$edgeifs = explode(',', $bridge['autoedge']);
924
		foreach ($edgeifs as $edgeif) {
925
			$realif = get_real_interface($edgeif);
926
			mwexec("/sbin/ifconfig {$bridgeif} -autoedge {$realif}");
927
		}
928
	}
929
	if (!empty($bridge['ptp'])) {
930
		$ptpifs = explode(',', $bridge['ptp']);
931
		foreach ($ptpifs as $ptpif) {
932
			$realif = get_real_interface($ptpif);
933
			mwexec("/sbin/ifconfig {$bridgeif} ptp {$realif}");
934
		}
935
	}
936
	if (!empty($bridge['autoptp'])) {
937
		$ptpifs = explode(',', $bridge['autoptp']);
938
		foreach ($ptpifs as $ptpif) {
939
			$realif = get_real_interface($ptpif);
940
			mwexec("/sbin/ifconfig {$bridgeif} -autoptp {$realif}");
941
		}
942
	}
943
	if (!empty($bridge['static'])) {
944
		$stickyifs = explode(',', $bridge['static']);
945
		foreach ($stickyifs as $stickyif) {
946
			$realif = get_real_interface($stickyif);
947
			mwexec("/sbin/ifconfig {$bridgeif} sticky {$realif}");
948
		}
949
	}
950
	if (!empty($bridge['private'])) {
951
		$privateifs = explode(',', $bridge['private']);
952
		foreach ($privateifs as $privateif) {
953
			$realif = get_real_interface($privateif);
954
			mwexec("/sbin/ifconfig {$bridgeif} private {$realif}");
955
		}
956
	}
957
}
958

    
959
function interface_bridge_configure_ip6linklocal($bridge) {
960
	$bridgeif = trim($bridge['bridgeif']);
961

    
962
	$members = explode(',', $bridge['members']);
963
	if (!count($members)) {
964
		return;
965
	}
966

    
967
	$auto_linklocal = isset($bridge['ip6linklocal']);
968
	$bridgeop = $auto_linklocal ? '' : '-';
969
	$memberop = $auto_linklocal ? '-' : '';
970

    
971
	mwexec("/usr/sbin/ndp -i {$bridgeif} -- {$bridgeop}auto_linklocal");
972
	foreach ($members as $member) {
973
		$realif = get_real_interface($member);
974
		mwexec("/usr/sbin/ndp -i {$realif} -- {$memberop}auto_linklocal");
975
	}
976
}
977

    
978
function interface_bridge_add_member($bridgeif, $interface, $flagsapplied = false) {
979
	global $config;
980

    
981
	if (!does_interface_exist($bridgeif) || !does_interface_exist($interface)) {
982
		return;
983
	}
984

    
985
	if ($flagsapplied == false) {
986
		$mtu = get_interface_mtu($bridgeif);
987
		$mtum = get_interface_mtu($interface);
988
		if ($mtu != $mtum && !(substr($interface, 0, 3) == "gif" && $mtu <= 1500)) {
989
			pfSense_interface_mtu($interface, $mtu);
990
		}
991

    
992
		hardware_offloading_applyflags($interface);
993
		interfaces_bring_up($interface);
994
	}
995

    
996
	pfSense_bridge_add_member($bridgeif, $interface);
997
	if (is_array($config['bridges']['bridged'])) {
998
		foreach ($config['bridges']['bridged'] as $bridge) {
999
			if ($bridgeif == $bridge['bridgeif']) {
1000
				interface_bridge_configure_stp($bridge);
1001
				interface_bridge_configure_advanced($bridge);
1002
			}
1003
		}
1004
	}
1005
}
1006

    
1007
function interfaces_lagg_configure($realif = "") {
1008
	global $config, $g;
1009
	$i = 0;
1010
	if (is_array($config['laggs']['lagg']) &&
1011
	    count($config['laggs']['lagg'])) {
1012
		if (platform_booting()) {
1013
			echo gettext("Configuring LAGG interfaces...");
1014
		}
1015
		foreach ($config['laggs']['lagg'] as $lagg) {
1016
			if (empty($lagg['laggif'])) {
1017
				$lagg['laggif'] = "lagg{$i}";
1018
			}
1019
			if (!empty($realif) && $realif != $lagg['laggif']) {
1020
				continue;
1021
			}
1022
			/* XXX: Maybe we should report any errors?! */
1023
			interface_lagg_configure($lagg, false);
1024
			$i++;
1025
		}
1026
		/* Invalidate cache */
1027
		get_interface_arr(true);
1028
		if (platform_booting()) {
1029
			echo gettext("done.") . "\n";
1030
		}
1031
	}
1032
}
1033

    
1034
function interface_lagg_configure($lagg, $flush = true) {
1035
	global $config, $g;
1036

    
1037
	if (!is_array($lagg)) {
1038
		return -1;
1039
	}
1040

    
1041
	$members = explode(',', $lagg['members']);
1042
	if (!count($members)) {
1043
		return -1;
1044
	}
1045

    
1046
	if (platform_booting() || !(empty($lagg['laggif']))) {
1047
		pfSense_interface_destroy($lagg['laggif']);
1048
		pfSense_interface_create2($lagg['laggif']);
1049
		$laggif = $lagg['laggif'];
1050
	} else {
1051
		$laggif = pfSense_interface_create2("lagg");
1052
	}
1053

    
1054
	/* Check if MTU was defined for this lagg interface */
1055
	$lagg_mtu = interface_find_child_cfgmtu($laggif);
1056
	if ($lagg_mtu == 0 &&
1057
	    is_array($config['interfaces'])) {
1058
		foreach ($config['interfaces'] as $tmpinterface) {
1059
			if ($tmpinterface['if'] == $lagg['laggif'] &&
1060
			    !empty($tmpinterface['mtu'])) {
1061
				$lagg_mtu = $tmpinterface['mtu'];
1062
				break;
1063
			}
1064
		}
1065
	}
1066

    
1067
	/* Just in case anything is not working well */
1068
	if ($lagg_mtu == 0) {
1069
		$lagg_mtu = 1500;
1070
	}
1071

    
1072
	// put failover master interface on top of list
1073
	if (($lagg['proto'] == 'failover') && isset($lagg['failovermaster']) &&
1074
	    ($lagg['failovermaster'] != 'auto')) {
1075
		unset($members[array_search($lagg['failovermaster'], $members)]);
1076
		$members = array_merge(array($lagg['failovermaster']), $members);
1077
	}
1078

    
1079
	if (($lagg['proto'] == 'lacp') && isset($lagg['lacptimeout']) &&
1080
	    ($lagg['lacptimeout'] != 'slow')) {
1081
		$lacptimeout = 'lacp_fast_timeout';
1082
	} else {
1083
		$lacptimeout = '';
1084
	}
1085

    
1086
	if ((($lagg['proto'] == 'lacp') || ($lagg['proto'] == 'loadbalance')) &&
1087
	    isset($lagg['lagghash']) && !empty($lagg['lagghash'])) {
1088
		$lagghash = 'lagghash ' . escapeshellarg($lagg['lagghash']);
1089
	} else {
1090
		$lagghash = '';
1091
	}
1092

    
1093
	foreach ($members as $member) {
1094
		if (!does_interface_exist($member)) {
1095
			continue;
1096
		}
1097

    
1098
		/* make sure the parent interface is up */
1099
		pfSense_interface_mtu($member, $lagg_mtu);
1100
		interfaces_bring_up($member);
1101
		hardware_offloading_applyflags($member);
1102

    
1103
		// Ensure there are no nulls in these values. It upsets escapeshellarg()
1104
		$laggif = str_replace("\0", "", $laggif);
1105
		$member = str_replace("\0", "", $member);
1106
		mwexec("/sbin/ifconfig " . escapeshellarg($laggif) . " laggport " . escapeshellarg($member));
1107
	}
1108

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

    
1111
	if ($flush) {
1112
		get_interface_arr(true);
1113
	}
1114

    
1115
	interfaces_bring_up($laggif);
1116

    
1117
	return $laggif;
1118
}
1119

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

    
1124
	if (!is_array($gre)) {
1125
		return -1;
1126
	}
1127

    
1128
	$realif = convert_friendly_interface_to_real_interface_name($gre['if']);
1129
	if (!interface_is_vlan($realif)) {
1130
		$realif = get_real_interface($gre['if']);
1131
	}
1132
	$realifip = get_interface_ip($gre['if']);
1133
	$realifip6 = get_interface_ipv6($gre['if']);
1134

    
1135
	/* do not run ifconfig without correct $realifip */
1136
	if ((!$realifip && is_ipaddrv4($gre['remote-addr'])) || 
1137
	    (!$realifip6 && is_ipaddrv6($gre['remote-addr']))) {
1138
		return -1;
1139
	}
1140

    
1141
	/* make sure the parent interface is up */
1142
	interfaces_bring_up($realif);
1143

    
1144
	if (platform_booting() || !(empty($gre['greif']))) {
1145
		pfSense_interface_destroy($gre['greif']);
1146
		pfSense_interface_create2($gre['greif']);
1147
		$greif = $gre['greif'];
1148
	} else {
1149
		$greif = pfSense_interface_create2("gre");
1150
	}
1151

    
1152
	$tunnel_type = '';
1153
	if ((!empty($gre['tunnel-local-addr'])) || (!empty($gre['tunnel-remote-addr']))) {
1154
		$tunnel_type = 'v4';
1155
	}
1156
	if ((!empty($gre['tunnel-local-addr6'])) || (!empty($gre['tunnel-remote-addr6']))) {
1157
		$tunnel_type .= 'v6';
1158
	}
1159

    
1160
	/* Do not change the order here for more see gre(4) NOTES section. */
1161
	if (is_ipaddrv6($gre['remote-addr'])) {
1162
		mwexec("/sbin/ifconfig {$greif} inet6 tunnel {$realifip6} " . escapeshellarg($gre['remote-addr']));
1163
	} else {
1164
		mwexec("/sbin/ifconfig {$greif} tunnel {$realifip} " . escapeshellarg($gre['remote-addr']));
1165
	}
1166
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1167
		mwexec("/sbin/ifconfig {$greif} " . escapeshellarg($gre['tunnel-local-addr']) . " " . escapeshellarg($gre['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gre['tunnel-remote-net']));
1168
	}
1169
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1170
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1171
		mwexec("/sbin/ifconfig {$greif} inet6 " . escapeshellarg($gre['tunnel-local-addr6']) . " " . escapeshellarg($gre['tunnel-remote-addr6']) . " prefixlen 128");
1172
	}
1173

    
1174
	$parentif = get_real_interface($gre['if']);
1175
	if ($parentif) {
1176
		interfaces_bring_up($parentif);
1177
	} else {
1178
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gre_configure()"));
1179
	}
1180

    
1181
	if (isset($gre['link1'])) {
1182
		if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1183
			mwexec("/sbin/route add " . escapeshellarg($gre['tunnel-remote-addr']) . "/" . escapeshellarg($gre['tunnel-remote-net']) . " " . escapeshellarg($gre['tunnel-local-addr']));
1184
		}
1185
		if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1186
			mwexec("/sbin/route -6 add " . escapeshellarg($gre['tunnel-remote-addr6']) . "/" . escapeshellarg($gre['tunnel-remote-net6']) . " " . escapeshellarg($gre['tunnel-local-addr6']));
1187
		}
1188
	}
1189
	if (in_array($tunnel_type, array('v4', 'v4v6'))) {
1190
		file_put_contents("{$g['tmp_path']}/{$greif}_router", $gre['tunnel-remote-addr']);
1191
		unlink_if_exists("{$g['tmp_path']}/{$greif}_router.last");
1192
	}
1193
	if (in_array($tunnel_type, array('v6', 'v4v6'))) {
1194
		file_put_contents("{$g['tmp_path']}/{$greif}_routerv6", $gre['tunnel-remote-addr6']);
1195
		unlink_if_exists("{$g['tmp_path']}/{$greif}_routerv6.last");
1196
	}
1197

    
1198
	if ($flush) {
1199
		get_interface_arr(true);
1200
	}
1201

    
1202
	interfaces_bring_up($greif);
1203

    
1204
	return $greif;
1205
}
1206

    
1207
function interface_is_type($if = NULL, $type) {
1208
	global $config;
1209
	switch ($type) {
1210
		case "gre":
1211
			$list = 'gres';
1212
			$entry = 'gre';
1213
			$entif = 'greif';
1214
			break;
1215
		case "gif":
1216
			$list = 'gifs';
1217
			$entry = 'gif';
1218
			$entif = 'gifif';
1219
			break;
1220
		case "lagg":
1221
			$list = 'laggs';
1222
			$entry = 'lagg';
1223
			$entif = 'laggif';
1224
			break;
1225
		default:
1226
			break;
1227
	}
1228

    
1229
	if (!isset($config[$list][$entry]) || !is_array($config[$list][$entry])) {
1230
		return (NULL);
1231
	}
1232

    
1233
	foreach ($config[$list][$entry] as $ent) {
1234
		if ($ent[$entif] == $if) {
1235
			return ($ent);
1236
		}
1237
	}
1238
	return (NULL);
1239
}
1240

    
1241
function is_greipsec($if) {
1242
	global $config;
1243

    
1244
	if (ipsec_enabled() && is_array($config['gres']) &&
1245
	    is_array($config['gres']['gre']) &&
1246
	    is_array($config['ipsec']['phase2'])) {
1247
		foreach ($config['gres']['gre'] as $gre) {
1248
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
1249
				foreach ($config['ipsec']['phase2'] as $ph2ent) {
1250
					if (($ph1ent['ikeid'] == $ph2ent['ikeid']) && ($ph2ent['mode'] == 'transport') &&
1251
					    !isset($ph1ent['disabled']) && !isset($ph2ent['disabled']) &&
1252
					    ($ph1ent['interface'] == $gre['if']) && ($gre['greif'] == $if) &&
1253
					    ($ph1ent['remote-gateway'] == $gre['remote-addr'])) {
1254
						    return true;
1255
					}
1256
				}
1257
			}
1258
		}
1259
	}
1260
	return false;
1261
}
1262

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

    
1267
	if (!is_array($gif)) {
1268
		return -1;
1269
	}
1270

    
1271
	$realif = convert_friendly_interface_to_real_interface_name($gif['if']);
1272
	if (!interface_is_vlan($realif)) {
1273
		$realif = get_real_interface($gif['if']);
1274
	}
1275
	$ipaddr = get_interface_ip($gif['if']);
1276

    
1277
	if (is_ipaddrv4($gif['remote-addr'])) {
1278
		if (is_ipaddrv4($ipaddr)) {
1279
			$realifip = $ipaddr;
1280
		} else {
1281
			$realifip = get_interface_ip($gif['if']);
1282
		}
1283
		$realifgw = get_interface_gateway($gif['if']);
1284
	} elseif (is_ipaddrv6($gif['remote-addr'])) {
1285
		if (is_ipaddrv6($ipaddr)) {
1286
			$realifip = $ipaddr;
1287
		} else {
1288
			$realifip = get_interface_ipv6($gif['if']);
1289
		}
1290
		$realifgw = get_interface_gateway_v6($gif['if']);
1291
	}
1292

    
1293
	/* do not run ifconfig without correct $realifip */
1294
	if ((!is_ipaddrv4($realifip) && is_ipaddrv4($gif['remote-addr'])) || 
1295
	    (!is_ipaddrv6($realifip) && is_ipaddrv6($gif['remote-addr']))) {
1296
		return -1;
1297
	}
1298

    
1299
	/* make sure the parent interface is up */
1300
	$parentif = get_real_interface($gif['if']);
1301
	if ($parentif) {
1302
		interfaces_bring_up($parentif);
1303
	} else {
1304
		log_error(gettext("could not bring parentif up -- variable not defined -- interface_gif_configure()"));
1305
	}
1306

    
1307
	if (platform_booting() || !(empty($gif['gifif']))) {
1308
		pfSense_interface_destroy($gif['gifif']);
1309
		pfSense_interface_create2($gif['gifif']);
1310
		$gifif = $gif['gifif'];
1311
	} else {
1312
		$gifif = pfSense_interface_create2("gif");
1313
	}
1314

    
1315
	/* Do not change the order here for more see gif(4) NOTES section. */
1316
	if (is_ipaddrv6($gif['remote-addr'])) {
1317
		mwexec("/sbin/ifconfig {$gifif} inet6 tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1318
	} else {
1319
		mwexec("/sbin/ifconfig {$gifif} tunnel {$realifip} " . escapeshellarg($gif['remote-addr']));
1320
	}
1321
	if ((is_ipaddrv6($gif['tunnel-local-addr'])) || (is_ipaddrv6($gif['tunnel-remote-addr']))) {
1322
		/* XXX: The prefixlen argument for tunnels of ipv6 is useless since it needs to be 128 as enforced by kernel */
1323
		//mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen /" . escapeshellarg($gif['tunnel-remote-net']));
1324
		mwexec("/sbin/ifconfig {$gifif} inet6 " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " prefixlen 128");
1325
	} else {
1326
		mwexec("/sbin/ifconfig {$gifif} " . escapeshellarg($gif['tunnel-local-addr']) . " " . escapeshellarg($gif['tunnel-remote-addr']) . " netmask " . gen_subnet_mask($gif['tunnel-remote-net']));
1327
	}
1328
	if (isset($gif['link1'])) {
1329
		pfSense_interface_flags($gifif, IFF_LINK1);
1330
	}
1331
	if (isset($gif['link2'])) {
1332
		pfSense_interface_flags($gifif, IFF_LINK2);
1333
	}
1334
	if ($gifif) {
1335
		interfaces_bring_up($gifif);
1336
		$gifmtu = "";
1337
		$currentgifmtu = get_interface_mtu($gifif);
1338
		foreach ($config['interfaces'] as $tmpinterface) {
1339
			if ($tmpinterface['if'] == $gifif) {
1340
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1341
					$gifmtu = $tmpinterface['mtu'];
1342
				}
1343
			}
1344
		}
1345
		if (is_numericint($gifmtu)) {
1346
			if ($gifmtu != $currentgifmtu) {
1347
				mwexec("/sbin/ifconfig {$gifif} mtu {$gifmtu}");
1348
			}
1349
		}
1350
	} else {
1351
		log_error(gettext("could not bring gifif up -- variable not defined"));
1352
	}
1353

    
1354
	if (!platform_booting()) {
1355
		$iflist = get_configured_interface_list();
1356
		foreach ($iflist as $ifname) {
1357
			if ($config['interfaces'][$ifname]['if'] == $gifif) {
1358
				if (get_interface_gateway($ifname)) {
1359
					system_routing_configure($ifname);
1360
					break;
1361
				}
1362
				if (get_interface_gateway_v6($ifname)) {
1363
					system_routing_configure($ifname);
1364
					break;
1365
				}
1366
			}
1367
		}
1368
	}
1369

    
1370

    
1371
	if (is_ipaddrv4($gif['tunnel-remote-addr'])) {
1372
		file_put_contents("{$g['tmp_path']}/{$gifif}_router",
1373
		    $gif['tunnel-remote-addr']);
1374
		unlink_if_exists("{$g['tmp_path']}/{$gifif}_router.last");
1375
	} elseif (is_ipaddrv6($gif['tunnel-remote-addr'])) {
1376
		file_put_contents("{$g['tmp_path']}/{$gifif}_routerv6",
1377
		    $gif['tunnel-remote-addr']);
1378
		unlink_if_exists("{$g['tmp_path']}/{$gifif}_routerv6.last");
1379
	}
1380

    
1381
	route_add_or_change($gif['remote-addr'], $realifgw);
1382

    
1383
	if ($flush) {
1384
		get_interface_arr(true);
1385
	}
1386

    
1387
	interfaces_bring_up($gifif);
1388

    
1389
	return $gifif;
1390
}
1391

    
1392
function interfaces_tunnel_configure($checkparent = 0, $realif = "", $type = "") {
1393
	global $config;
1394

    
1395
	if (!in_array($type, array('gre', 'gif'))) {
1396
		return;
1397
	}
1398

    
1399
	if (!is_array($config["{$type}s"][$type]) ||
1400
	    !count($config["{$type}s"][$type])) {
1401
		return;
1402
	}
1403

    
1404
	foreach ($config["{$type}s"][$type] as $i => $tunnel) {
1405
		if (empty($tunnel["{$type}if"])) {
1406
			$tunnel["{$type}if"] = $type . $i;
1407
		}
1408
		if (!empty($realif) && $realif != $tunnel["{$type}if"]) {
1409
			continue;
1410
		}
1411

    
1412
		if ($checkparent == 1) {
1413
			if (substr($tunnel['if'], 0, 4) == '_vip') {
1414
				continue;
1415
			}
1416
			if (substr($tunnel['if'], 0, 5) == '_lloc') {
1417
				continue;
1418
			}
1419
			if (!empty($config['interfaces'][$tunnel['if']]) &&
1420
			    $config['interfaces'][$tunnel['if']]['ipaddrv6'] ==
1421
			    "track6") {
1422
				continue;
1423
			}
1424
		} elseif ($checkparent == 2) {
1425
			if ((substr($tunnel['if'], 0, 4) != '_vip' &&
1426
			    substr($tunnel['if'], 0, 5) != '_lloc') &&
1427
			    (empty($config['interfaces'][$tunnel['if']]) ||
1428
			    $config['interfaces'][$tunnel['if']]['ipaddrv6'] !=
1429
			    "track6")) {
1430
				continue;
1431
			}
1432
		}
1433
		if ($type == 'gif') {
1434
			interface_gif_configure($tunnel, "", false);
1435
		} elseif ($type == 'gre') {
1436
			interface_gre_configure($tunnel, "", false);
1437
		}
1438
	}
1439

    
1440
	/* Invalidate cache */
1441
	get_interface_arr(true);
1442
}
1443

    
1444
/* Build a list of IPsec interfaces */
1445
function interface_ipsec_vti_list_p1($ph1ent) {
1446
	global $config;
1447
	$iface_list = array();
1448

    
1449
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1450
		return $iface_list;
1451
	}
1452

    
1453
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1454
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1455
		return $iface_list;
1456
	}
1457

    
1458
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1459
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1460
		foreach ($vtisubnet_spec as $vtisub) {
1461
			$iface_list[ipsec_get_ifname($ph1ent, $vtisub['reqid'])] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr'] . " / " . $vtisub['descr']);
1462
		}
1463
	} else {
1464
		/* For IKEv2, only create one interface with additional addresses as aliases */
1465
		$iface_list[ipsec_get_ifname($ph1ent)] = gettext("IPsec VTI") . ": ".htmlspecialchars($ph1ent['descr']);
1466
	}
1467
	return $iface_list;
1468
}
1469
function interface_ipsec_vti_list_all() {
1470
	global $config;
1471
	$iface_list = array();
1472
	if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
1473
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1474
			if ($ph1ent['disabled']) {
1475
				continue;
1476
			}
1477
			$iface_list = array_merge($iface_list, interface_ipsec_vti_list_p1($ph1ent));
1478
		}
1479
	}
1480
	return $iface_list;
1481
}
1482

    
1483
function is_interface_ipsec_vti_assigned($phase2) {
1484
	$phase1 = ipsec_get_phase1($phase2['ikeid']);
1485
	$vti_interface = null;
1486
	$vtisubnet_spec = ipsec_vti($phase1, true);
1487
	if (($vtisubnet_spec && is_array($vtisubnet_spec))) {
1488
		/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1489
		if (!isset($phase1['mobile']) && ($phase1['iketype'] == 'ikev1' || isset($phase1['splitconn']))) {
1490
			foreach ($vtisubnet_spec as $idx => $vtisub) {
1491
				/* Is this for this P2? */
1492
				if (($vtisub['left'] == ipsec_idinfo_to_cidr($phase2['localid'], true, $phase2['mode'])) &&
1493
				    ($vtisub['right'] == ipsec_idinfo_to_cidr($phase2['remoteid'], false, $phase2['mode']))) {
1494
					$vti_interface = ipsec_get_ifname($phase1, $vtisub['reqid']);
1495
				}
1496
			}
1497
		} else {
1498
			$vti_interface = ipsec_get_ifname($phase1);
1499
		}
1500
	}
1501
	/* Check if this interface is assigned */
1502
	return (does_interface_exist($vti_interface) && (convert_real_interface_to_friendly_interface_name($vti_interface) != null));
1503
}
1504
function interface_ipsec_vti_configure($ph1ent, $gateways_status = false) {
1505
	global $config, $ipsec_reqid_base;
1506

    
1507
	if (empty($ph1ent) || !is_array($ph1ent) || !is_array($config['ipsec']['phase2'])) {
1508
		return false;
1509
	}
1510

    
1511
	$vtisubnet_spec = ipsec_vti($ph1ent, true);
1512
	if ((!$vtisubnet_spec || !is_array($vtisubnet_spec))) {
1513
		return false;
1514
	}
1515

    
1516
	$left_spec = ipsec_get_phase1_src($ph1ent, $gateways_status);
1517

    
1518
	/* Attempt to resolve the remote gateway if needed */
1519
	$right_spec = ipsec_get_phase1_dst($ph1ent);
1520
	if (empty($right_spec)) {
1521
		/* Far end cannot be resolved */
1522
		return false;
1523
	}
1524

    
1525
	$iface_addrs = array();
1526
	$reqids = array();
1527

    
1528
	/* With IKEv1 or v2+Split, each P2 gets its own conn/reqid/interface */
1529
	if (!isset($ph1ent['mobile']) && ($ph1ent['iketype'] == 'ikev1' || isset($ph1ent['splitconn']))) {
1530
		/* Form a single interface for each P2 entry */
1531
		foreach ($vtisubnet_spec as $idx => $vtisub) {
1532
			$ipsecif = ipsec_get_ifname($ph1ent, $vtisub['reqid']);
1533
			if (!is_array($iface_addrs[$ipsecif])) {
1534
				$iface_addrs[$ipsecif] = array();
1535
			}
1536
			$vtisub['alias'] = "";
1537
			$iface_addrs[$ipsecif][] = $vtisub;
1538
			$reqids[$ipsecif] = $vtisub['reqid'];
1539
		}
1540
	} else {
1541
		/* For IKEv2, only create one interface with additional addresses as aliases */
1542
		$ipsecif = ipsec_get_ifname($ph1ent);
1543
		if (!is_array($iface_addrs[$ipsecif])) {
1544
			$iface_addrs[$ipsecif] = array();
1545
		}
1546
		$have_v4 = false;
1547
		$have_v6 = false;
1548
		foreach ($vtisubnet_spec as $vtisub) {
1549
			// Alias stuff
1550
			$vtisub['alias'] = "";
1551
			if (is_ipaddrv6($vtisub['left'])) {
1552
				if ($have_v6) {
1553
					$vtisub['alias'] = " alias";
1554
				}
1555
				$have_v6 = true;
1556
			} else {
1557
				if ($have_v4) {
1558
					$vtisub['alias'] = " alias";
1559
				}
1560
				$have_v4 = true;
1561
			}
1562
			$iface_addrs[$ipsecif][] = $vtisub;
1563
		}
1564
		/* IKEv2 w/o Split uses the reqid of the first P2 */
1565
		$reqids[$ipsecif] = $vtisubnet_spec[0]['reqid'];
1566
	}
1567

    
1568
	foreach ($iface_addrs as $ipsecif => $addrs) {
1569
		if (!is_array($addrs)) {
1570
			continue;
1571
		}
1572
		// Create IPsec interface
1573
		if (does_interface_exist($ipsecif)) {
1574
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " destroy");
1575
		}
1576
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " create reqid " . escapeshellarg($ipsec_reqid_base + $reqids[$ipsecif]));
1577

    
1578
		/* Apply the outer tunnel addresses to the interface */
1579
		$inet = is_ipaddrv6($left_spec) ? "inet6" : "inet";
1580
		mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} tunnel " . escapeshellarg($left_spec) . " " . escapeshellarg($right_spec) . " up");
1581

    
1582
		/* Loop through all of the addresses for this interface and apply them as needed */
1583
		foreach ($addrs as $addr) {
1584
			// apply interface addresses
1585
			if (is_v6($addr['left'])) {
1586
				$inet = "inet6";
1587
				$gwtype = "v6";
1588
				$right = '';
1589
			} else {
1590
				$inet = "inet";
1591
				$gwtype = "";
1592
				$right = escapeshellarg($addr['right']);
1593
			}
1594

    
1595
			mwexec("/sbin/ifconfig " . escapeshellarg($ipsecif) . " {$inet} " . escapeshellarg($addr['left']) . " " . $right . $addr['alias']);
1596
			/* If alias is empty, this is the first address on the interface and should be used as the gateway. */
1597
			if (empty($addr['alias'])) {
1598
				file_put_contents("/tmp/{$ipsecif}_router{$gwtype}", $addr['right']);
1599
				unlink_if_exists("/tmp/{$ipsecif}_router{$gwtype}.last");
1600
			}
1601
		}
1602
		/* Check/set the MTU if the user configured a custom value.
1603
		 * https://redmine.pfsense.org/issues/9111 */
1604
		$currentvtimtu = get_interface_mtu($ipsecif);
1605
		foreach ($config['interfaces'] as $tmpinterface) {
1606
			if ($tmpinterface['if'] == $ipsecif) {
1607
				if (isset($tmpinterface['mtu']) && is_numericint($tmpinterface['mtu'])) {
1608
					$vtimtu = $tmpinterface['mtu'];
1609
				}
1610
			}
1611
		}
1612
		if (is_numericint($vtimtu)) {
1613
			if ($vtimtu != $currentvtimtu) {
1614
				mwexec("/sbin/ifconfig {$ipsecif} mtu {$vtimtu}");
1615
			}
1616
		}
1617
		system_routing_configure(convert_real_interface_to_friendly_interface_name($ipsecif));
1618
	}
1619
	return true;
1620
}
1621

    
1622
function interfaces_ipsec_vti_configure($gateways_status = false) {
1623
	global $config;
1624

    
1625
	/* Fetch gateway status if not passed */
1626
	if (!is_array($gateways_status)) {
1627
		$gateways_status = return_gateways_status(true);
1628
	}
1629
	if (is_array($config['ipsec']) &&
1630
	    is_array($config['ipsec']['phase1']) &&
1631
	    is_array($config['ipsec']['phase2'])) {
1632
		foreach ($config['ipsec']['phase1'] as $ph1ent) {
1633
			if ($ph1ent['disabled']) {
1634
				continue;
1635
			}
1636
			if (interface_ipsec_vti_configure($ph1ent, $gateways_status) &&
1637
			    !$bootmsg && platform_booting()) {
1638
				echo gettext("Configuring IPsec VTI interfaces...");
1639
				$bootmsg = true;
1640
			}
1641
		}
1642
	}
1643
	if (platform_booting() && $bootmsg) {
1644
		echo gettext("done.") . "\n";
1645
	}
1646
}
1647

    
1648
function interfaces_configure() {
1649
	global $config, $g;
1650

    
1651
	/* Set up our loopback interface */
1652
	interfaces_loopback_configure();
1653

    
1654
	/* create the unconfigured wireless clones */
1655
	interfaces_create_wireless_clones();
1656

    
1657
	/* set up LAGG virtual interfaces */
1658
	interfaces_lagg_configure();
1659

    
1660
	/* set up VLAN virtual interfaces */
1661
	interfaces_vlan_configure();
1662

    
1663
	interfaces_qinq_configure(false);
1664

    
1665
	$iflist = get_configured_interface_with_descr();
1666
	$delayed_list = array();
1667
	$bridge_list = array();
1668
	$track6_list = array();
1669
	$dhcp6c_list = array();
1670

    
1671
	/* This is needed to speedup interfaces on bootup. */
1672
	$reload = false;
1673
	if (!platform_booting()) {
1674
		$reload = true;
1675
	}
1676

    
1677
	foreach ($iflist as $if => $ifname) {
1678
		$realif = $config['interfaces'][$if]['if'];
1679
		if (strstr($realif, "bridge")) {
1680
			$bridge_list[$if] = $ifname;
1681
		} elseif (strstr($realif, "gre")) {
1682
			$delayed_list[$if] = $ifname;
1683
		} elseif (strstr($realif, "gif")) {
1684
			$delayed_list[$if] = $ifname;
1685
		} elseif (strstr($realif, "ovpn")) {
1686
			continue;
1687
		} elseif (strstr($realif, "ipsec")) {
1688
			continue;
1689
		} elseif (!empty($config['interfaces'][$if]['ipaddrv6']) &&
1690
		    $config['interfaces'][$if]['ipaddrv6'] == "track6") {
1691
			$track6_list[$if] = $ifname;
1692
		} else {
1693
			/* do not run dhcp6c if track interface does not exists
1694
			 * see https://redmine.pfsense.org/issues/3965
1695
			 * and https://redmine.pfsense.org/issues/11633 */ 
1696
			if (!empty($config['interfaces'][$if]['ipaddrv6']) &&
1697
			    $config['interfaces'][$if]['ipaddrv6'] == "dhcp6") {
1698
				$tr6list = link_interface_to_track6($if);
1699
				if (is_array($tr6list) && !empty($tr6list)) {
1700
					$dhcp6c_list[$if] = $ifname;
1701
					continue;
1702
				}
1703
			}
1704
			if (platform_booting()) {
1705
				printf(gettext("Configuring %s interface..."),
1706
				    $ifname);
1707
			}
1708

    
1709
			if ($g['debug']) {
1710
				log_error(sprintf(gettext("Configuring %s"),
1711
				    $ifname));
1712
			}
1713
			interface_configure($if, $reload);
1714
			if (platform_booting()) {
1715
				echo gettext("done.") . "\n";
1716
			}
1717
		}
1718
	}
1719

    
1720
	/*
1721
	 * NOTE: The following function parameter consists of
1722
	 *	1 - Do not load gre/gif/bridge with parent/member as vip
1723
	 *	2 - Do load gre/gif/bridge with parent/member as vip
1724
	 */
1725

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

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

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

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

    
1743
		interface_configure($if, $reload);
1744

    
1745
		if (platform_booting()) {
1746
			echo gettext("done.") . "\n";
1747
		}
1748
	}
1749

    
1750
	/* bring up vip interfaces */
1751
	interfaces_vips_configure();
1752

    
1753
	/* set up GRE virtual interfaces */
1754
	interfaces_tunnel_configure(2,'','gre');
1755

    
1756
	/* set up GIF virtual interfaces */
1757
	interfaces_tunnel_configure(2,'','gif');
1758

    
1759
	foreach ($delayed_list as $if => $ifname) {
1760
		if (platform_booting()) {
1761
			printf(gettext("Configuring %s interface..."), $ifname);
1762
		}
1763
		if ($g['debug']) {
1764
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1765
		}
1766

    
1767
		interface_configure($if, $reload);
1768

    
1769
		if (platform_booting()) {
1770
			echo gettext("done.") . "\n";
1771
		}
1772
	}
1773

    
1774
	/* set up BRIDGE virtual interfaces */
1775
	interfaces_bridge_configure(2);
1776

    
1777
	foreach ($bridge_list as $if => $ifname) {
1778
		if (platform_booting()) {
1779
			printf(gettext("Configuring %s interface..."), $ifname);
1780
		}
1781
		if ($g['debug']) {
1782
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1783
		}
1784

    
1785
		// bridge interface needs reconfigure, then re-add VIPs, to ensure find_interface_ip is correct.
1786
		// redmine #3997
1787
		interface_reconfigure($if, $reload);
1788
		interfaces_vips_configure($if);
1789

    
1790
		if (platform_booting()) {
1791
			echo gettext("done.") . "\n";
1792
		}
1793
	}
1794

    
1795
	foreach ($dhcp6c_list as $if => $ifname) {
1796
		if (platform_booting()) {
1797
			printf(gettext("Configuring %s interface..."), $ifname);
1798
		}
1799
		if ($g['debug']) {
1800
			log_error(sprintf(gettext("Configuring %s"), $ifname));
1801
		}
1802

    
1803
		interface_configure($if, $reload);
1804

    
1805
		if (platform_booting()) {
1806
			echo gettext("done.") . "\n";
1807
		}
1808
	}
1809

    
1810
	/* set up IPsec VTI interfaces */
1811
	interfaces_ipsec_vti_configure();
1812

    
1813
	/* configure interface groups */
1814
	interfaces_group_setup();
1815

    
1816
	if (!platform_booting()) {
1817
		/* reconfigure static routes (kernel may have deleted them) */
1818
		system_routing_configure();
1819

    
1820
		/* reload IPsec tunnels */
1821
		ipsec_configure();
1822

    
1823
		/* restart dns servers (defering dhcpd reload) */
1824
		if (isset($config['dnsmasq']['enable'])) {
1825
			services_dnsmasq_configure(false);
1826
		}
1827
		if (isset($config['unbound']['enable'])) {
1828
			services_unbound_configure(false);
1829
		}
1830

    
1831
		/* reload dhcpd (interface enabled/disabled status may have changed) */
1832
		services_dhcpd_configure();
1833
	}
1834

    
1835
	return 0;
1836
}
1837

    
1838
function interface_reconfigure($interface = "wan", $reloadall = false) {
1839
	interface_bring_down($interface);
1840
	interface_configure($interface, $reloadall);
1841
}
1842

    
1843
function interface_vip_bring_down($vip) {
1844
	global $g;
1845

    
1846
	$vipif = get_real_interface($vip['interface']);
1847
	switch ($vip['mode']) {
1848
		case "proxyarp":
1849
			if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
1850
				killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
1851
			}
1852
			break;
1853
		case "ipalias":
1854
			if (does_interface_exist($vipif)) {
1855
				if (is_ipaddrv6($vip['subnet'])) {
1856
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " -alias");
1857
				} else {
1858
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1859
				}
1860
			}
1861
			break;
1862
		case "carp":
1863
			/* XXX: Is enough to delete ip address? */
1864
			if (does_interface_exist($vipif)) {
1865
				if (is_ipaddrv6($vip['subnet'])) {
1866
					mwexec("/sbin/ifconfig {$vipif} inet6 " . escapeshellarg($vip['subnet']) . " delete");
1867
				} else {
1868
					pfSense_interface_deladdress($vipif, $vip['subnet']);
1869
				}
1870
			}
1871
			break;
1872
	}
1873
}
1874

    
1875
function interface_bring_down($interface = "wan", $destroy = false, $ifacecfg = false) {
1876
	global $config, $g;
1877

    
1878
	if (!isset($config['interfaces'][$interface])) {
1879
		return;
1880
	}
1881

    
1882
	if ($g['debug']) {
1883
		log_error(sprintf(gettext('Calling interface down for interface %1$s, destroy is %2$s'), $interface, (($destroy) ? 'true' : 'false')));
1884
	}
1885

    
1886
	/*
1887
	 * NOTE: The $realifv6 is needed when WANv4 is type PPP and v6 is DHCP and the option v6 from v4 is used.
1888
	 * In this case the real $realif of v4 is different from that of v6 for operation.
1889
	 * Keep this in mind while doing changes here!
1890
	 */
1891
	if ($ifacecfg === false) {
1892
		$ifcfg = $config['interfaces'][$interface];
1893
		$ppps = $config['ppps']['ppp'];
1894
		$realif = get_real_interface($interface);
1895
		$realifv6 = get_real_interface($interface, "inet6", true);
1896
	} elseif (!is_array($ifacecfg)) {
1897
		log_error(gettext("Wrong parameters used during interface_bring_down"));
1898
		$ifcfg = $config['interfaces'][$interface];
1899
		$ppps = $config['ppps']['ppp'];
1900
		$realif = get_real_interface($interface);
1901
		$realifv6 = get_real_interface($interface, "inet6", true);
1902
	} else {
1903
		$ifcfg = $ifacecfg['ifcfg'];
1904
		$ppps = $ifacecfg['ppps'];
1905
		if (isset($ifacecfg['ifcfg']['realif'])) {
1906
			$realif = $ifacecfg['ifcfg']['realif'];
1907
			/* XXX: Any better way? */
1908
			$realifv6 = $realif;
1909
		} else {
1910
			$realif = get_real_interface($interface);
1911
			$realifv6 = get_real_interface($interface, "inet6", true);
1912
		}
1913
	}
1914

    
1915
	/* check all gateways, including dynamic,
1916
	 * see https://redmine.pfsense.org/issues/12920 */
1917
	foreach (return_gateways_array(true) as $gw) {
1918
		if ($gw['friendlyiface'] == $interface) {
1919
			$restart_gateways_monitor = true;
1920
			break;
1921
		}
1922
	}
1923

    
1924
	switch ($ifcfg['ipaddr']) {
1925
		case "ppp":
1926
		case "pppoe":
1927
		case "pptp":
1928
		case "l2tp":
1929
			if (is_array($ppps) && count($ppps)) {
1930
				foreach ($ppps as $pppid => $ppp) {
1931
					if ($realif == $ppp['if']) {
1932
						if (isset($ppp['ondemand']) && !$destroy) {
1933
							send_event("interface reconfigure {$interface}");
1934
							break;
1935
						}
1936
						if (file_exists("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid")) {
1937
							killbypid("{$g['varrun_path']}/{$ppp['type']}_{$interface}.pid");
1938
							sleep(2);
1939
						}
1940
						unlink_if_exists("{$g['varetc_path']}/mpd_{$interface}.conf");
1941
						break;
1942
					}
1943
				}
1944
			}
1945
			break;
1946
		case "dhcp":
1947
			kill_dhclient_process($realif);
1948
			unlink_if_exists("{$g['varetc_path']}/dhclient_{$interface}.conf");
1949
			if (does_interface_exist("$realif")) {
1950
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1951
				interface_vip_cleanup($interface, "inet4");
1952
				if ($destroy == true) {
1953
					pfSense_interface_flags($realif, -IFF_UP);
1954
				}
1955
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1956
			}
1957
			break;
1958
		default:
1959
			if (does_interface_exist("$realif")) {
1960
				mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " delete", true);
1961
				interface_vip_cleanup($interface, "inet4");
1962
				if ($destroy == true) {
1963
					pfSense_interface_flags($realif, -IFF_UP);
1964
				}
1965
				mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
1966
			}
1967
			break;
1968
	}
1969

    
1970
	$track6 = array();
1971
	switch ($ifcfg['ipaddrv6']) {
1972
		case "slaac":
1973
		case "dhcp6":
1974
			interface_dhcpv6_configure($interface, $ifcfg, true);
1975
			if (does_interface_exist($realifv6)) {
1976
				mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 -accept_rtadv");
1977
				$ip6 = find_interface_ipv6($realifv6);
1978
				if (is_ipaddrv6($ip6) && $ip6 != "::") {
1979
					mwexec("/sbin/ifconfig " . escapeshellarg($realifv6) . " inet6 {$ip6} delete", true);
1980
				}
1981
				interface_vip_cleanup($interface, "inet6");
1982
				if ($destroy == true) {
1983
					pfSense_interface_flags($realif, -IFF_UP);
1984
				}
1985
			}
1986
			$track6 = link_interface_to_track6($interface);
1987
			break;
1988
		case "6rd":
1989
		case "6to4":
1990
			$realif = "{$interface}_stf";
1991
			if (does_interface_exist("$realif")) {
1992
				/* destroy stf interface if tunnel is being disabled or tunnel type is being changed */
1993
				if (($ifcfg['ipaddrv6'] == '6rd' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6rd')) ||
1994
				    ($ifcfg['ipaddrv6'] == '6to4' && (!isset($config['interfaces'][$interface]['ipaddrv6']) || $config['interfaces'][$interface]['ipaddrv6'] != '6to4'))) {
1995
					$destroy = true;
1996
				} else {
1997
					/* get_interface_ipv6() returns empty value if interface is being disabled */
1998
					$ip6 = get_interface_ipv6($interface);
1999
					if (is_ipaddrv6($ip6)) {
2000
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2001
					}
2002
				}
2003
				interface_vip_cleanup($interface, "inet6");
2004
				if ($destroy == true) {
2005
					pfSense_interface_flags($realif, -IFF_UP);
2006
				}
2007
			}
2008
			$track6 = link_interface_to_track6($interface);
2009
			break;
2010
		default:
2011
			if (does_interface_exist("$realif")) {
2012
				$ip6 = get_interface_ipv6($interface);
2013
				if (is_ipaddrv6($ip6)) {
2014
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ip6} delete", true);
2015
				}
2016
				if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
2017
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$ifcfg['ipaddrv6']} delete", true);
2018
				}
2019
				interface_vip_cleanup($interface, "inet6");
2020
				if ($destroy == true) {
2021
					pfSense_interface_flags($realif, -IFF_UP);
2022
				}
2023
				//mwexec("/usr/sbin/arp -d -i " . escapeshellarg($realif) . " -a");
2024
			}
2025
			$track6 = link_interface_to_track6($interface);
2026
			break;
2027
	}
2028

    
2029
	if (!empty($track6) && is_array($track6)) {
2030
		if (!function_exists('services_dhcpd_configure')) {
2031
			require_once('services.inc');
2032
		}
2033
		/* Bring down radvd and dhcp6 on these interfaces */
2034
		services_dhcpd_configure('inet6', $track6);
2035
	}
2036

    
2037
	$old_router = '';
2038
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
2039
		$old_router = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"));
2040
	}
2041

    
2042
	/* remove interface up file if it exists */
2043
	unlink_if_exists("{$g['tmp_path']}/{$realif}up");
2044
	unlink_if_exists("{$g['vardb_path']}/{$interface}ip");
2045
	unlink_if_exists("{$g['vardb_path']}/{$interface}ipv6");
2046
	if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
2047
		rename("{$g['tmp_path']}/{$realif}_router", "{$g['tmp_path']}/{$realif}_router.last");
2048
	}
2049
	if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
2050
		rename("{$g['tmp_path']}/{$realif}_routerv6", "{$g['tmp_path']}/{$realif}_routerv6.last");
2051
	}
2052
	unlink_if_exists("{$g['varetc_path']}/nameserver_{$realif}");
2053
	unlink_if_exists("{$g['varetc_path']}/nameserver_v6{$interface}");
2054
	unlink_if_exists("{$g['varetc_path']}/searchdomain_{$realif}");
2055
	unlink_if_exists("{$g['varetc_path']}/searchdomain_v6{$interface}");
2056
	unlink_if_exists("{$g['tmp_path']}/{$interface}_upstart4");
2057
	unlink_if_exists("{$g['tmp_path']}/{$interface}_upstart6");
2058

    
2059
	/* hostapd and wpa_supplicant do not need to be running when the interface is down.
2060
	 * They will also use 100% CPU if running after the wireless clone gets deleted. */
2061
	if (is_array($ifcfg['wireless'])) {
2062
		kill_hostapd($realif);
2063
		mwexec(kill_wpasupplicant($realif));
2064
		unlink_if_exists("{$g['varetc_path']}/wpa_supplicant_{$realif}.*");
2065
		unlink_if_exists("{$g['varetc_path']}/hostapd_{$realif}.conf");
2066
	}
2067

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

    
2072
			/* Invalidate cache */
2073
			get_interface_arr(true);
2074
		}
2075
	}
2076

    
2077
	/* If interface has a gateway, we need to bounce dpinger to keep dpinger happy */
2078
	if ($restart_gateways_monitor) {
2079
		setup_gateways_monitor();
2080
	}
2081

    
2082
	return;
2083
}
2084

    
2085
function interfaces_carp_set_maintenancemode($carp_maintenancemode) {
2086
	global $config;
2087
	if (isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == false) {
2088
		unset($config["virtualip_carp_maintenancemode"]);
2089
		write_config("Leave CARP maintenance mode");
2090
	} elseif (!isset($config["virtualip_carp_maintenancemode"]) && $carp_maintenancemode == true) {
2091
		$config["virtualip_carp_maintenancemode"] = true;
2092
		write_config(gettext("Enter CARP maintenance mode"));
2093
	}
2094
	init_config_arr(array('virtualip', 'vip'));
2095
	$viparr = &$config['virtualip']['vip'];
2096

    
2097
	if (is_array($viparr)) {
2098
		foreach ($viparr as $vip) {
2099
			if ($vip['mode'] == "carp") {
2100
				interface_carp_configure($vip, true);
2101
			}
2102
		}
2103
	}
2104
}
2105

    
2106
function interface_wait_tentative($interface, $timeout = 10) {
2107
	if (!does_interface_exist($interface)) {
2108
		return false;
2109
	}
2110

    
2111
	$time = 0;
2112
	while ($time <= $timeout) {
2113
		$if = pfSense_get_interface_addresses($interface);
2114
		if (!isset($if['tentative'])) {
2115
			return true;
2116
		}
2117
		sleep(1);
2118
		$time++;
2119
	}
2120

    
2121
	return false;
2122
}
2123

    
2124
function interface_isppp_type($interface) {
2125
	global $config;
2126

    
2127
	if (!is_array($config['interfaces'][$interface])) {
2128
		return false;
2129
	}
2130

    
2131
	switch ($config['interfaces'][$interface]['ipaddr']) {
2132
		case 'pptp':
2133
		case 'l2tp':
2134
		case 'pppoe':
2135
		case 'ppp':
2136
			return true;
2137
			break;
2138
		default:
2139
			return false;
2140
			break;
2141
	}
2142
}
2143

    
2144
function interfaces_ptpid_used($ptpid) {
2145
	global $config;
2146

    
2147
	if (is_array($config['ppps']['ppp'])) {
2148
		foreach ($config['ppps']['ppp'] as & $settings) {
2149
			if ($ptpid == $settings['ptpid']) {
2150
				return true;
2151
			}
2152
		}
2153
	}
2154

    
2155
	return false;
2156
}
2157

    
2158
function interfaces_ptpid_next() {
2159

    
2160
	$ptpid = 0;
2161
	while (interfaces_ptpid_used($ptpid)) {
2162
		$ptpid++;
2163
	}
2164

    
2165
	return $ptpid;
2166
}
2167

    
2168
function getMPDCRONSettings($pppif) {
2169
	global $config;
2170

    
2171
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2172
	if (is_array($config['cron']['item'])) {
2173
		foreach ($config['cron']['item'] as $i => $item) {
2174
			if (stripos($item['command'], $cron_cmd_file) !== false) {
2175
				return array("ID" => $i, "ITEM" => $item);
2176
			}
2177
		}
2178
	}
2179

    
2180
	return NULL;
2181
}
2182

    
2183
function handle_pppoe_reset($post_array) {
2184
	global $config, $g;
2185

    
2186
	$pppif = "{$post_array['type']}{$post_array['ptpid']}";
2187
	$cron_cmd_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
2188

    
2189
	if (!is_array($config['cron']['item'])) {
2190
		$config['cron']['item'] = array();
2191
	}
2192

    
2193
	$itemhash = getMPDCRONSettings($pppif);
2194

    
2195
	// reset cron items if necessary and return
2196
	if (empty($post_array['pppoe-reset-type'])) {
2197
		if (isset($itemhash)) {
2198
			unset($config['cron']['item'][$itemhash['ID']]);
2199
		}
2200
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
2201
		return;
2202
	}
2203

    
2204
	if (empty($itemhash)) {
2205
		$itemhash = array();
2206
	}
2207
	$item = array();
2208
	if (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "custom") {
2209
		$item['minute'] = $post_array['pppoe_resetminute'] ? $post_array['pppoe_resetminute'] : "*";
2210
		$item['hour'] = $post_array['pppoe_resethour'] ? $post_array['pppoe_resethour'] : "*";
2211
		if (isset($post_array['pppoe_resetdate']) && $post_array['pppoe_resetdate'] <> "") {
2212
			$date = explode("/", $post_array['pppoe_resetdate']);
2213
			$item['mday'] = $date[1];
2214
			$item['month'] = $date[0];
2215
		} else {
2216
			$item['mday'] = "*";
2217
			$item['month'] = "*";
2218
		}
2219
		$item['wday'] = "*";
2220
		$item['who'] = "root";
2221
		$item['command'] = $cron_cmd_file;
2222
	} elseif (isset($post_array['pppoe-reset-type']) && $post_array['pppoe-reset-type'] == "preset") {
2223
		switch ($post_array['pppoe_pr_preset_val']) {
2224
			case "monthly":
2225
				$item['minute'] = "0";
2226
				$item['hour'] = "0";
2227
				$item['mday'] = "1";
2228
				$item['month'] = "*";
2229
				$item['wday'] = "*";
2230
				break;
2231
			case "weekly":
2232
				$item['minute'] = "0";
2233
				$item['hour'] = "0";
2234
				$item['mday'] = "*";
2235
				$item['month'] = "*";
2236
				$item['wday'] = "0";
2237
				break;
2238
			case "daily":
2239
				$item['minute'] = "0";
2240
				$item['hour'] = "0";
2241
				$item['mday'] = "*";
2242
				$item['month'] = "*";
2243
				$item['wday'] = "*";
2244
				break;
2245
			case "hourly":
2246
				$item['minute'] = "0";
2247
				$item['hour'] = "*";
2248
				$item['mday'] = "*";
2249
				$item['month'] = "*";
2250
				$item['wday'] = "*";
2251
				break;
2252
		} // end switch
2253
		$item['who'] = "root";
2254
		$item['command'] = $cron_cmd_file;
2255
	}
2256
	if (empty($item)) {
2257
		return;
2258
	}
2259
	if (isset($itemhash['ID'])) {
2260
		$config['cron']['item'][$itemhash['ID']] = $item;
2261
	} else {
2262
		$config['cron']['item'][] = $item;
2263
	}
2264
}
2265

    
2266
function restart_ppp_interfaces_using_interfaces($triggerinterfaces) {
2267
	global $config;
2268
	$ppp_list = array();
2269
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2270
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2271
			$ports = explode(",", $ppp['ports']);
2272
			foreach($ports as $port) {
2273
				foreach($triggerinterfaces as $vip) {
2274
					if ($port == "_vip{$vip['uniqid']}") {
2275
						$if = convert_real_interface_to_friendly_interface_name($ppp['if']);
2276
						$ppp_list[$if] = 1;
2277
					}
2278
				}
2279
			}
2280
		}
2281
	}
2282
	foreach($ppp_list as $pppif => $dummy) {
2283
		interface_ppps_configure($pppif);
2284
	}
2285
}
2286

    
2287
/*
2288
 * This function can configure PPPoE, MLPPP (PPPoE), PPTP.
2289
 * It writes the mpd config file to /var/etc every time the link is opened.
2290
 */
2291
function interface_ppps_configure($interface) {
2292
	global $config, $g;
2293

    
2294
	/* Return for unassigned interfaces. This is a minimum requirement. */
2295
	if (empty($config['interfaces'][$interface])) {
2296
		return 0;
2297
	}
2298
	$ifcfg = $config['interfaces'][$interface];
2299
	if (!isset($ifcfg['enable'])) {
2300
		return 0;
2301
	}
2302

    
2303
	// mpd5 requires a /var/spool/lock directory for PPP modem links.
2304
	if (!is_dir("/var/spool/lock")) {
2305
		mkdir("/var/spool/lock", 0777, true);
2306
	}
2307
	// mpd5 modem chat script expected in the same directory as the mpd_xxx.conf files
2308
	if (!file_exists("{$g['varetc_path']}/mpd.script")) {
2309
		@symlink("/usr/local/sbin/mpd.script", "{$g['varetc_path']}/mpd.script");
2310
	}
2311

    
2312
	if (is_array($config['ppps']['ppp']) && count($config['ppps']['ppp'])) {
2313
		foreach ($config['ppps']['ppp'] as $pppid => $ppp) {
2314
			if ($ifcfg['if'] == $ppp['if']) {
2315
				break;
2316
			}
2317
		}
2318
	}
2319
	if (!$ppp || $ifcfg['if'] != $ppp['if']) {
2320
		log_error(sprintf(gettext("Can't find PPP config for %s in interface_ppps_configure()."), $ifcfg['if']));
2321
		return 0;
2322
	}
2323
	$pppif = $ifcfg['if'];
2324
	if ($ppp['type'] == "ppp") {
2325
		$type = "modem";
2326
	} else {
2327
		$type = $ppp['type'];
2328
	}
2329
	$upper_type = strtoupper($ppp['type']);
2330

    
2331
	$confports = explode(',', $ppp['ports']);
2332
	if ($type == "modem") {
2333
		$ports = $confports;
2334
	} else {
2335
		$ports = array();
2336
		foreach ($confports as $pid => $port) {
2337
			if (strstr($port, "_vip")) {
2338
				if (get_carp_interface_status($port) != "MASTER") {
2339
					continue;
2340
				}
2341
			}
2342
			$ports[$pid] = get_real_interface($port);
2343
			if (empty($ports[$pid])) {
2344
				return 0;
2345
			}
2346
		}
2347
	}
2348
	$localips = explode(',', $ppp['localip']);
2349
	$gateways = explode(',', $ppp['gateway']);
2350
	$subnets = explode(',', $ppp['subnet']);
2351

    
2352
	/* We bring up the parent interface first because if DHCP is configured on the parent we need
2353
	 * to obtain an address first so we can write it in the mpd .conf file for PPTP and L2TP configs
2354
	 */
2355
	foreach ($ports as $pid => $port) {
2356
		switch ($ppp['type']) {
2357
			case "pppoe":
2358
				/* Bring the parent interface up */
2359
				interfaces_bring_up($port);
2360
				/* Enable setautosrc to automatically change mac address if parent interface's changes */
2361
				$ngif = str_replace(".", "_", $port);
2362
				mwexec("/usr/sbin/ngctl msg {$ngif}: setautosrc 1");
2363
				break;
2364
			case "pptp":
2365
			case "l2tp":
2366
				/* configure interface */
2367
				if (is_ipaddr($localips[$pid])) {
2368
					// Manually configure interface IP/subnet
2369
					pfSense_interface_setaddress($port, "{$localips[$pid]}/{$subnets[$pid]}");
2370
					interfaces_bring_up($port);
2371
				} elseif (empty($localips[$pid])) {
2372
					$localips[$pid] = get_interface_ip($port); // try to get the interface IP from the port
2373
				}
2374

    
2375
				if (!is_ipaddr($localips[$pid])) {
2376
					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));
2377
					$localips[$pid] = "0.0.0.0";
2378
				}
2379
				if (!$g['booting'] && !is_ipaddr($gateways[$pid]) && is_hostname($gateways[$pid])) {
2380
					$gateways[$pid] = gethostbyname($gateways[$pid]);
2381
				}
2382
				if (!is_ipaddr($gateways[$pid])) {
2383
					log_error(sprintf(gettext('Could not get a PPTP/L2TP Remote IP address from %1$s for %2$s in interfaces_ppps_configure.'), $dhcp_gateway, $gway));
2384
					return 0;
2385
				}
2386
				break;
2387
			case "ppp":
2388
				if (!file_exists("{$port}")) {
2389
					log_error(sprintf(gettext("Device %s does not exist. PPP link cannot start without the modem device."), $port));
2390
					return 0;
2391
				}
2392
				break;
2393
			default:
2394
				log_error(sprintf(gettext("Unknown %s configured as ppp interface."), $type));
2395
				break;
2396
		}
2397
	}
2398

    
2399
	if (isset($ppp['pppoe-multilink-over-singlelink']) ||
2400
	    (is_array($ports) && count($ports) > 1)) {
2401
		$multilink = "enable";
2402
	} else {
2403
		$multilink = "disable";
2404
	}
2405

    
2406
	if ($type == "modem") {
2407
		if (is_ipaddr($ppp['localip'])) {
2408
			$localip = $ppp['localip'];
2409
		} else {
2410
			$localip = '0.0.0.0';
2411
		}
2412

    
2413
		if (is_ipaddr($ppp['gateway'])) {
2414
			$gateway = $ppp['gateway'];
2415
		} else {
2416
			$gateway = "10.64.64.{$pppid}";
2417
		}
2418
		$ranges = "{$localip}/0 {$gateway}/0";
2419

    
2420
		if (empty($ppp['apnum'])) {
2421
			$ppp['apnum'] = 1;
2422
		}
2423
	} else {
2424
		$ranges = "0.0.0.0/0 0.0.0.0/0";
2425
	}
2426

    
2427
	if (isset($ppp['ondemand'])) {
2428
		$ondemand = "enable";
2429
	} else {
2430
		$ondemand = "disable";
2431
	}
2432
	if (!isset($ppp['idletimeout'])) {
2433
		$ppp['idletimeout'] = 0;
2434
	}
2435

    
2436
	if (empty($ppp['username']) && $type == "modem") {
2437
		$ppp['username'] = "user";
2438
		$ppp['password'] = "none";
2439
	}
2440
	if (empty($ppp['password']) && $type == "modem") {
2441
		$passwd = "none";
2442
	} else {
2443
		$passwd = base64_decode($ppp['password']);
2444
	}
2445

    
2446
	$bandwidths = explode(',', $ppp['bandwidth']);
2447
	$defaultmtu = "1492";
2448
	if (!empty($ifcfg['mtu'])) {
2449
		$defaultmtu = intval($ifcfg['mtu']);
2450
	}
2451
	if (isset($ppp['mtu'])) {
2452
		$mtus = explode(',', $ppp['mtu']);
2453
	}
2454
	if (isset($ppp['mru'])) {
2455
		$mrus = explode(',', $ppp['mru']);
2456
	}
2457
	if (isset($ppp['mrru'])) {
2458
		$mrrus = explode(',', $ppp['mrru']);
2459
	}
2460
	if (!empty($ifcfg['ipaddrv6'])) {
2461
		$ipv6cp = "set bundle enable ipv6cp";
2462
	}
2463

    
2464
	// Construct the mpd.conf file
2465
	$mpdconf = <<<EOD
2466
startup:
2467
	# configure the console
2468
	set console close
2469
	# configure the web server
2470
	set web close
2471

    
2472
default:
2473
{$ppp['type']}client:
2474
	create bundle static {$interface}
2475
	{$ipv6cp}
2476
	set iface name {$pppif}
2477

    
2478
EOD;
2479

    
2480
	if (isset($ifcfg['descr'])) {
2481
		$mpdconf .= <<<EOD
2482
	set iface description "{$ifcfg['descr']}"
2483

    
2484
EOD;
2485
	}
2486
	$setdefaultgw = false;
2487
	$defgw4 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw4']);
2488
//	$defgw6 = lookup_gateway_or_group_by_name($config['gateways']['defaultgw6']);
2489
	if ($defgw4['interface'] == $interface) {
2490
		$setdefaultgw = true;
2491
	}
2492

    
2493
/* Omit this, we maintain the default route by other means, and it causes problems with
2494
 * default gateway switching. See redmine #1837 for original issue
2495
 * re-enabling this for now to fix issue with missing default gateway with PPPoE in some
2496
 * edge case. redmine #6495 open to address.
2497
 */
2498
	if ($setdefaultgw == true) {
2499
		$mpdconf .= <<<EOD
2500
	set iface route default
2501

    
2502
EOD;
2503
	}
2504

    
2505
	$mpdconf .= <<<EOD
2506
	set iface {$ondemand} on-demand
2507
	set iface idle {$ppp['idletimeout']}
2508

    
2509
EOD;
2510

    
2511
	if (isset($ppp['ondemand'])) {
2512
		$mpdconf .= <<<EOD
2513
	set iface addrs 10.10.1.1 10.10.1.2
2514

    
2515
EOD;
2516
	}
2517

    
2518
	if (isset($ppp['mtu-override']) &&
2519
	    !isset($ppp['pppoe-multilink-over-singlelink'])) {
2520
		/* Find the smaller MTU set on ports */
2521
		$mtu = $defaultmtu;
2522
		foreach ($ports as $pid => $port) {
2523
			if (empty($mtus[$pid])) {
2524
				$mtus[$pid] = $defaultmtu;
2525
			}
2526
			if ($type == "pppoe") {
2527
				if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2528
					$mtus[$pid] = get_interface_mtu($port) - 8;
2529
				}
2530
			}
2531
			if ($mtu > $mtus[$pid]) {
2532
				$mtu = $mtus[$pid];
2533
			}
2534
		}
2535
		$mpdconf .= <<<EOD
2536
	set iface mtu {$mtu} override
2537

    
2538
EOD;
2539
	}
2540

    
2541
	if (isset($ppp['tcpmssfix'])) {
2542
		$tcpmss = "disable";
2543
	} else {
2544
		$tcpmss = "enable";
2545
	}
2546
	$mpdconf .= <<<EOD
2547
	set iface {$tcpmss} tcpmssfix
2548

    
2549
EOD;
2550

    
2551
	$mpdconf .= <<<EOD
2552
	set iface up-script /usr/local/sbin/ppp-linkup
2553
	set iface down-script /usr/local/sbin/ppp-linkdown
2554
	set ipcp ranges {$ranges}
2555

    
2556
EOD;
2557
	if (isset($ppp['vjcomp'])) {
2558
		$mpdconf .= <<<EOD
2559
	set ipcp no vjcomp
2560

    
2561
EOD;
2562
	}
2563

    
2564
	if (isset($config['system']['dnsallowoverride'])) {
2565
		$mpdconf .= <<<EOD
2566
	set ipcp enable req-pri-dns
2567
	set ipcp enable req-sec-dns
2568

    
2569
EOD;
2570
	}
2571

    
2572
	if (!isset($ppp['verbose_log'])) {
2573
		$mpdconf .= <<<EOD
2574
	#log -bund -ccp -chat -iface -ipcp -lcp -link
2575

    
2576
EOD;
2577
	}
2578

    
2579
	foreach ($ports as $pid => $port) {
2580
		$port = get_real_interface($port);
2581
		$mpdconf .= <<<EOD
2582

    
2583
	create link static {$interface}_link{$pid} {$type}
2584
	set link action bundle {$interface}
2585
	set link {$multilink} multilink
2586
	set link keep-alive 10 60
2587
	set link max-redial 0
2588

    
2589
EOD;
2590
		if (isset($ppp['shortseq'])) {
2591
			$mpdconf .= <<<EOD
2592
	set link no shortseq
2593

    
2594
EOD;
2595
		}
2596

    
2597
		if (isset($ppp['acfcomp'])) {
2598
			$mpdconf .= <<<EOD
2599
	set link no acfcomp
2600

    
2601
EOD;
2602
		}
2603

    
2604
		if (isset($ppp['protocomp'])) {
2605
			$mpdconf .= <<<EOD
2606
	set link no protocomp
2607

    
2608
EOD;
2609
		}
2610

    
2611
		$mpdconf .= <<<EOD
2612
	set link disable chap pap
2613
	set link accept chap pap eap
2614
	set link disable incoming
2615

    
2616
EOD;
2617

    
2618

    
2619
		if (!empty($bandwidths[$pid])) {
2620
			$mpdconf .= <<<EOD
2621
	set link bandwidth {$bandwidths[$pid]}
2622

    
2623
EOD;
2624
		}
2625

    
2626
		if (empty($mtus[$pid])) {
2627
			$mtus[$pid] = $defaultmtu;
2628
		}
2629
		if ($type == "pppoe") {
2630
			if ($mtus[$pid] > (get_interface_mtu($port) - 8)) {
2631
				$mtus[$pid] = get_interface_mtu($port) - 8;
2632
			}
2633
		}
2634
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2635
		    !isset($ppp['mtu-override']) &&
2636
		    !($type == "pppoe" && $mtus[$pid] > 1492)) {
2637
			// N.B. MTU for PPPoE with MTU > 1492 is set using pppoe max-payload - see below
2638
			$mpdconf .= <<<EOD
2639
	set link mtu {$mtus[$pid]}
2640

    
2641
EOD;
2642
		}
2643

    
2644
		if (!isset($ppp['pppoe-multilink-over-singlelink']) &&
2645
		    !isset($ppp['mtu-override']) &&
2646
		    !empty($mrus[$pid])) {
2647
			$mpdconf .= <<<EOD
2648
	set link mru {$mrus[$pid]}
2649

    
2650
EOD;
2651
		}
2652

    
2653
		if (!empty($mrrus[$pid])) {
2654
			$mpdconf .= <<<EOD
2655
	set link mrru {$mrrus[$pid]}
2656

    
2657
EOD;
2658
		}
2659

    
2660
		$mpdconf .= <<<EOD
2661
	set auth authname "{$ppp['username']}"
2662
	set auth password {$passwd}
2663

    
2664
EOD;
2665
		if ($type == "modem") {
2666
			$mpdconf .= <<<EOD
2667
	set modem device {$ppp['ports']}
2668
	set modem script DialPeer
2669
	set modem idle-script Ringback
2670
	set modem watch -cd
2671
	set modem var \$DialPrefix "DT"
2672
	set modem var \$Telephone "{$ppp['phone']}"
2673

    
2674
EOD;
2675
		}
2676
		if (isset($ppp['connect-timeout']) && $type == "modem") {
2677
			$mpdconf .= <<<EOD
2678
	set modem var \$ConnectTimeout "{$ppp['connect-timeout']}"
2679

    
2680
EOD;
2681
		}
2682
		if (isset($ppp['initstr']) && $type == "modem") {
2683
			$initstr = base64_decode($ppp['initstr']);
2684
			$mpdconf .= <<<EOD
2685
	set modem var \$InitString "{$initstr}"
2686

    
2687
EOD;
2688
		}
2689
		if (isset($ppp['simpin']) && $type == "modem") {
2690
			if ($ppp['pin-wait'] == "") {
2691
				$ppp['pin-wait'] = 0;
2692
			}
2693
			$mpdconf .= <<<EOD
2694
	set modem var \$SimPin "{$ppp['simpin']}"
2695
	set modem var \$PinWait "{$ppp['pin-wait']}"
2696

    
2697
EOD;
2698
		}
2699
		if (isset($ppp['apn']) && $type == "modem") {
2700
			$mpdconf .= <<<EOD
2701
	set modem var \$APN "{$ppp['apn']}"
2702
	set modem var \$APNum "{$ppp['apnum']}"
2703

    
2704
EOD;
2705
		}
2706
		if ($type == "pppoe") {
2707
			$hostuniq = '';
2708
			if (!empty($ppp['hostuniq'])) {
2709
				if (preg_match('/^0x[a-fA-F0-9]+$/', $ppp['hostuniq'])) {
2710
					$hostuniq = strtolower($ppp['hostuniq']) .'|';
2711
				} elseif (preg_match('/^[a-zA-Z0-9]+$/i', $ppp['hostuniq'])) {
2712
					$hostuniq = '0x' . bin2hex($ppp['hostuniq']) . '|';
2713
				}
2714
			}
2715
			// Send a null service name if none is set.
2716
			$provider = isset($ppp['provider']) ? $ppp['provider'] : "";
2717
			$mpdconf .= <<<EOD
2718
	set pppoe service "{$hostuniq}{$provider}"
2719

    
2720
EOD;
2721
		}
2722
		if (($type == "pppoe") && ($mtus[$pid] > 1492)) {
2723
			$mpdconf .= <<<EOD
2724
	set pppoe max-payload {$mtus[$pid]}
2725

    
2726
EOD;
2727
		}
2728
		if ($type == "pppoe") {
2729
			$mpdconf .= <<<EOD
2730
	set pppoe iface {$port}
2731

    
2732
EOD;
2733
		}
2734

    
2735
		if (($type == "l2tp") && !empty($ppp['secret'])) {
2736
			$secret = str_replace('"', '\"', base64_decode($ppp['secret']));
2737
			$mpdconf .= <<<EOD
2738
	set l2tp secret "{$secret}"
2739

    
2740
EOD;
2741
		}
2742

    
2743
		if (($type == "pptp") || ($type == "l2tp")) {
2744
			$mpdconf .= <<<EOD
2745
	set {$type} self {$localips[$pid]}
2746
	set {$type} peer {$gateways[$pid]}
2747

    
2748
EOD;
2749
		}
2750

    
2751
		$mpdconf .= "\topen\n";
2752
	} //end foreach ($port)
2753

    
2754

    
2755
	/* Generate mpd.conf. If mpd_[interface].conf exists in the conf path, then link to it instead of generating a fresh conf file. */
2756
	if (file_exists("{$g['conf_path']}/mpd_{$interface}.conf")) {
2757
		@symlink("{$g['conf_path']}/mpd_{$interface}.conf", "{$g['varetc_path']}/mpd_{$interface}.conf");
2758
	} else {
2759
		$fd = fopen("{$g['varetc_path']}/mpd_{$interface}.conf", "w");
2760
		if (!$fd) {
2761
			log_error(sprintf(gettext('Error: cannot open mpd_%1$s.conf in interface_ppps_configure().%2$s'), $interface, "\n"));
2762
			return 0;
2763
		}
2764
		// Write out mpd_ppp.conf
2765
		fwrite($fd, $mpdconf);
2766
		fclose($fd);
2767
		unset($mpdconf);
2768
	}
2769

    
2770
	// Create the uptime log if requested and if it doesn't exist already, or delete it if it is no longer requested.
2771
	if (isset($ppp['uptime'])) {
2772
		if (!file_exists("/conf/{$pppif}.log")) {
2773
			file_put_contents("/conf/{$pppif}.log", '');
2774
		}
2775
	} else {
2776
		if (file_exists("/conf/{$pppif}.log")) {
2777
			@unlink("/conf/{$pppif}.log");
2778
		}
2779
	}
2780

    
2781
	/* clean up old lock files */
2782
	foreach ($ports as $port) {
2783
		if (file_exists("{$g['var_path']}/spool/lock/LCK..{$port}")) {
2784
			unlink("{$g['var_path']}/spool/lock/LCK..{$port}");
2785
		}
2786
	}
2787

    
2788
	/* Set temporary bogon (RFC 5737) IPv4 addresses to work round mpd5 IPv6CP issue causing */
2789
	/* random IPv6 interface identifier during boot. More details at */
2790
	/* https://forum.netgate.com/post/592474 */
2791
	if (platform_booting() && is_array($config['interfaces'])) {
2792
		$count = 0;
2793
		foreach ($config['interfaces'] as $tempifacename => $tempiface) {
2794
			if ((isset($tempiface['if'])) && (isset($tempiface['ipaddr']) || isset($tempiface['ipaddrv6'])) && !interface_isppp_type($tempifacename)) {
2795
				$tempaddr[$count]['if'] = $tempiface['if'];
2796
				$tempaddr[$count]['ipaddr'] = '192.0.2.' . strval (10 + ($count * 2)) . '/31';
2797
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempaddr[$count]['if']) . ' inet ' . escapeshellarg($tempaddr[$count]['ipaddr']) . ' alias', true);
2798
				$count++;
2799
			}
2800
			// Maximum /31 is is x.y.z.254/31
2801
			if ($count > 122) {
2802
				break;
2803
			}
2804
		}
2805
		unset($count);
2806
	}
2807

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

    
2813
	// Check for PPPoE periodic reset request
2814
	if ($type == "pppoe") {
2815
		if (!empty($ppp['pppoe-reset-type'])) {
2816
			interface_setup_pppoe_reset_file($ppp['if'], $interface);
2817
		} else {
2818
			interface_setup_pppoe_reset_file($ppp['if']);
2819
		}
2820
	}
2821
	/* wait for upto 30 seconds for the interface to appear (ppp(oe)) */
2822
	$i = 0;
2823
	while ($i < 10) {
2824
		if (does_interface_exist($ppp['if'], true)) {
2825
			break;
2826
		}
2827
		sleep(3);
2828
		$i++;
2829
	}
2830

    
2831
	/* Remove all temporary bogon IPv4 addresses */
2832
	if (is_array($tempaddr)) {
2833
		foreach ($tempaddr as $tempiface) {
2834
			if (isset($tempiface['if']) && isset($tempiface['ipaddr'])) {
2835
				mwexec('/sbin/ifconfig ' . escapeshellarg($tempiface['if']) . ' inet ' . escapeshellarg($tempiface['ipaddr']) . ' -alias', true);
2836
			}
2837
		}
2838
		unset ($tempaddr);
2839
	}
2840

    
2841
	/* we only support the 3gstats.php for huawei modems for now. Will add more later. */
2842
	/* We should be able to launch the right version for each modem */
2843
	/* We can also guess the mondev from the manufacturer */
2844
	exec("/usr/sbin/usbconfig | /usr/bin/egrep -ie '(huawei)'", $usbmodemoutput);
2845
	mwexec("/bin/ps auxww | /usr/bin/grep \"{$interface}\" | /usr/bin/grep \"[3]gstats\" | /usr/bin/awk '{print $2}' | /usr/bin/xargs kill");
2846
	foreach ($ports as $port) {
2847
		if (preg_match("/huawei/i", implode("\n", $usbmodemoutput))) {
2848
			$mondev = substr(basename($port), 0, -1);
2849
			$devlist = glob("/dev/{$mondev}?");
2850
			$mondev = basename(end($devlist));
2851
		}
2852
		if (preg_match("/zte/i", implode("\n", $usbmodemoutput))) {
2853
			$mondev = substr(basename($port), 0, -1) . "1";
2854
		}
2855
		if ($mondev != '') {
2856
			log_error(sprintf(gettext('Starting 3gstats.php on device \'%1$s\' for interface \'%2$s\''), $mondev, $interface));
2857
			mwexec_bg("/usr/local/bin/3gstats.php {$mondev} {$interface}");
2858
		}
2859
	}
2860

    
2861
	return 1;
2862
}
2863

    
2864
function interfaces_sync_setup() {
2865
	global $g, $config;
2866

    
2867
	if (isset($config['system']['developerspew'])) {
2868
		$mt = microtime();
2869
		echo "interfaces_sync_setup() being called $mt\n";
2870
	}
2871

    
2872
	if (platform_booting()) {
2873
		echo gettext("Configuring CARP settings...");
2874
		mute_kernel_msgs();
2875
	}
2876

    
2877
	/* suck in configuration items */
2878
	if ($config['hasync']) {
2879
		$pfsyncenabled = $config['hasync']['pfsyncenabled'];
2880
		$pfsyncinterface = $config['hasync']['pfsyncinterface'];
2881
		$pfsyncpeerip = $config['hasync']['pfsyncpeerip'];
2882
	}
2883

    
2884
	set_sysctl(array(
2885
		"net.inet.carp.preempt" => "1",
2886
		"net.inet.carp.log" => "1")
2887
	);
2888

    
2889
	if (!empty($pfsyncinterface)) {
2890
		$carp_sync_int = get_real_interface($pfsyncinterface);
2891
	}
2892

    
2893
	/* setup pfsync interface */
2894
	if (isset($carp_sync_int) and isset($pfsyncenabled)) {
2895
		if (is_ipaddr($pfsyncpeerip)) {
2896
			$syncpeer = "syncpeer {$pfsyncpeerip}";
2897
		} else {
2898
			$syncpeer = "-syncpeer";
2899
		}
2900

    
2901
		mwexec("/sbin/ifconfig pfsync0 syncdev {$carp_sync_int} " .
2902
		    "{$syncpeer} up");
2903
		mwexec("/sbin/ifconfig pfsync0 -defer");
2904

    
2905
		/*
2906
		 * XXX: Handle an issue with pfsync(4) and carp(4). In a
2907
		 * cluster carp will come up before pfsync(4) has updated and
2908
		 * so will cause issues for existing sessions.
2909
		 */
2910
		log_error(gettext("waiting for pfsync..."));
2911

    
2912
		$i = 0;
2913
		do {
2914
			sleep(1);
2915
			$_gb = exec('/sbin/ifconfig pfsync0 | ' .
2916
			    '/usr/bin/grep -q "syncok: 0" 2>/dev/null', $output,
2917
			    $rc);
2918
			$i++;
2919
		} while ($rc != 0 && $i <= 30);
2920

    
2921
		log_error(sprintf(gettext("pfsync done in %s seconds."), $i));
2922
		log_error(gettext("Configuring CARP settings finalize..."));
2923
	} else {
2924
		mwexec("/sbin/ifconfig pfsync0 -syncdev -syncpeer down");
2925
	}
2926

    
2927
	$carplist = get_configured_vip_list('all', VIP_CARP);
2928
	if (is_array($carplist) && count($carplist) > 0) {
2929
		set_single_sysctl("net.inet.carp.allow", "1");
2930
	} else {
2931
		set_single_sysctl("net.inet.carp.allow", "0");
2932
	}
2933

    
2934
	if (platform_booting()) {
2935
		unmute_kernel_msgs();
2936
		echo gettext("done.") . "\n";
2937
	}
2938
}
2939

    
2940
function interface_proxyarp_configure($interface = "") {
2941
	global $config, $g;
2942
	if (isset($config['system']['developerspew'])) {
2943
		$mt = microtime();
2944
		echo "interface_proxyarp_configure() being called $mt\n";
2945
	}
2946

    
2947
	/* kill any running choparp */
2948
	if (empty($interface)) {
2949
		killbyname("choparp");
2950
	} else {
2951
		$vipif = get_real_interface($interface);
2952
		if (file_exists("{$g['varrun_path']}/choparp_{$vipif}.pid")) {
2953
			killbypid("{$g['varrun_path']}/choparp_{$vipif}.pid");
2954
		}
2955
	}
2956

    
2957
	$paa = array();
2958
	if (!empty($config['virtualip']) && is_array($config['virtualip']['vip'])) {
2959

    
2960
		/* group by interface */
2961
		foreach ($config['virtualip']['vip'] as $vipent) {
2962
			if ($vipent['mode'] === "proxyarp") {
2963
				if ($vipent['interface']) {
2964
					$proxyif = $vipent['interface'];
2965
				} else {
2966
					$proxyif = "wan";
2967
				}
2968

    
2969
				if (!empty($interface) && $interface != $proxyif) {
2970
					continue;
2971
				}
2972

    
2973
				if (!is_array($paa[$proxyif])) {
2974
					$paa[$proxyif] = array();
2975
				}
2976

    
2977
				$paa[$proxyif][] = $vipent;
2978
			}
2979
		}
2980
	}
2981

    
2982
	if (!empty($interface)) {
2983
		if (is_array($paa[$interface])) {
2984
			$paaifip = get_interface_ip($interface);
2985
			if (!is_ipaddr($paaifip)) {
2986
				return;
2987
			}
2988
			$vipif = get_real_interface($interface);
2989
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
2990
			$args .= $vipif . " auto";
2991
			foreach ($paa[$interface] as $paent) {
2992
				if (isset($paent['subnet'])) {
2993
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
2994
				} elseif (isset($paent['range'])) {
2995
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
2996
				}
2997
			}
2998
			mwexec_bg("/usr/local/sbin/choparp " . $args);
2999
		}
3000
	} elseif (count($paa) > 0) {
3001
		foreach ($paa as $paif => $paents) {
3002
			$paaifip = get_interface_ip($paif);
3003
			if (!is_ipaddr($paaifip)) {
3004
				continue;
3005
			}
3006
			$vipif = get_real_interface($paif);
3007
			$args  = "-p {$g['varrun_path']}/choparp_{$vipif}.pid ";
3008
			$args .= $vipif . " auto";
3009
			foreach ($paents as $paent) {
3010
				if (isset($paent['subnet'])) {
3011
					$args .= " " . escapeshellarg("{$paent['subnet']}/{$paent['subnet_bits']}");
3012
				} elseif (isset($paent['range'])) {
3013
					$args .= " " . escapeshellarg($paent['range']['from'] . "-" . $paent['range']['to']);
3014
				}
3015
			}
3016
			mwexec_bg("/usr/local/sbin/choparp " . $args);
3017
		}
3018
	}
3019
}
3020

    
3021
function interface_vip_cleanup($interface, $inet = "all", $type = VIP_ALL) {
3022
	global $g, $config;
3023

    
3024
	if (is_array($config['virtualip']['vip'])) {
3025
		foreach ($config['virtualip']['vip'] as $vip) {
3026

    
3027
			$iface = $vip['interface'];
3028
			if (substr($iface, 0, 4) == "_vip")
3029
				$iface = get_configured_vip_interface($vip['interface']);
3030
			if ($iface != $interface)
3031
				continue;
3032
			if ($type == VIP_CARP) {
3033
				if ($vip['mode'] != "carp")
3034
					continue;
3035
			} elseif ($type == VIP_IPALIAS) {
3036
				if ($vip['mode'] != "ipalias")
3037
					continue;
3038
			} else {
3039
				if ($vip['mode'] != "carp" && $vip['mode'] != "ipalias")
3040
					continue;
3041
			}
3042

    
3043
			if ($inet == "inet6" && is_ipaddrv6($vip['subnet']))
3044
				interface_vip_bring_down($vip);
3045
			elseif ($inet == "inet4" && is_ipaddrv4($vip['subnet']))
3046
				interface_vip_bring_down($vip);
3047
			elseif ($inet == "all")
3048
				interface_vip_bring_down($vip);
3049
		}
3050
	}
3051
}
3052

    
3053
function interfaces_vips_configure($interface = "") {
3054
	global $g, $config;
3055
	if (isset($config['system']['developerspew'])) {
3056
		$mt = microtime();
3057
		echo "interfaces_vips_configure() being called $mt\n";
3058
	}
3059

    
3060
	if (!is_array($config['virtualip']['vip'])) {
3061
		return;
3062
	}
3063

    
3064
	$carp_setuped = false;
3065
	$anyproxyarp = false;
3066
	foreach ($config['virtualip']['vip'] as $vip) {
3067
		if ($interface <> "" &&
3068
		    get_root_interface($vip['interface']) <> $interface) {
3069
			continue;
3070
		}
3071
		switch ($vip['mode']) {
3072
			case "proxyarp":
3073
				/*
3074
				 * nothing it is handled on
3075
				 * interface_proxyarp_configure()
3076
				 */
3077
				$anyproxyarp = true;
3078
				break;
3079
			case "ipalias":
3080
				interface_ipalias_configure($vip);
3081
				break;
3082
			case "carp":
3083
				if ($carp_setuped == false) {
3084
					$carp_setuped = true;
3085
				}
3086
				interface_carp_configure($vip);
3087
				break;
3088
		}
3089
	}
3090
	if ($carp_setuped == true) {
3091
		interfaces_sync_setup();
3092
	}
3093
	if ($anyproxyarp == true) {
3094
		interface_proxyarp_configure();
3095
	}
3096
}
3097

    
3098
function interface_ipalias_configure(&$vip) {
3099
	global $config;
3100

    
3101
	$gateway = '';
3102
	if ($vip['mode'] != 'ipalias') {
3103
		return;
3104
	}
3105

    
3106
	$realif = get_real_interface("_vip{$vip['uniqid']}");
3107
	if ($realif != "lo0") {
3108
		$if = convert_real_interface_to_friendly_interface_name($realif);
3109
		if (!isset($config['interfaces'][$if]) ||
3110
		    !isset($config['interfaces'][$if]['enable'])) {
3111
			return;
3112
		}
3113
		if (is_pseudo_interface($realif)) {
3114
			if (is_ipaddrv4($vip['subnet'])) {
3115
				$gateway = get_interface_gateway($if);
3116
			} else {
3117
				$gateway = get_interface_gateway_v6($if);
3118
			}
3119
		}
3120
	}
3121

    
3122
	$af = 'inet';
3123
	if (is_ipaddrv6($vip['subnet'])) {
3124
		$af = 'inet6';
3125
	}
3126
	$iface = $vip['interface'];
3127
	$vhid = '';
3128
	if (substr($vip['interface'], 0, 4) == "_vip") {
3129
		$carpvip = get_configured_vip($vip['interface']);
3130
		$iface = $carpvip['interface'];
3131
		$vhid = "vhid {$carpvip['vhid']}";
3132
	}
3133
	mwexec("/sbin/ifconfig " . escapeshellarg($realif) ." {$af} ". escapeshellarg($vip['subnet']) ."/" . escapeshellarg($vip['subnet_bits']) . " alias {$gateway} {$vhid}");
3134
	unset($iface, $af, $realif, $carpvip, $vhid, $gateway);
3135
}
3136

    
3137
function interface_carp_configure(&$vip, $maintenancemode_only = false) {
3138
	global $config, $g;
3139
	if (isset($config['system']['developerspew'])) {
3140
		$mt = microtime();
3141
		echo "interface_carp_configure() being called $mt\n";
3142
	}
3143

    
3144
	if ($vip['mode'] != "carp") {
3145
		return;
3146
	}
3147

    
3148
	$realif = get_real_interface($vip['interface']);
3149
	if (!does_interface_exist($realif)) {
3150
		file_notice("CARP", sprintf(gettext(
3151
		    "Interface specified for the virtual IP address %s does not exist. Skipping this VIP."),
3152
		    $vip['subnet']), "Firewall: Virtual IP", "");
3153
		return;
3154
	}
3155
	if ($realif != "lo0") {
3156
		if (!isset($config['interfaces'][$vip['interface']]) ||
3157
		    !isset($config['interfaces'][$vip['interface']]['enable'])) {
3158
			return;
3159
		}
3160
	}
3161

    
3162
	$vip_password = $vip['password'];
3163
	$vip_password = escapeshellarg(addslashes(str_replace(" ", "",
3164
	    $vip_password)));
3165
	if ($vip['password'] != "") {
3166
		$password = " pass {$vip_password}";
3167
	}
3168

    
3169
	$advbase = "";
3170
	if (!empty($vip['advbase'])) {
3171
		$advbase = "advbase " . escapeshellarg($vip['advbase']);
3172
	}
3173

    
3174
	$carp_maintenancemode = isset(
3175
	    $config["virtualip_carp_maintenancemode"]);
3176
	if ($carp_maintenancemode) {
3177
		$advskew = "advskew 254";
3178
	} else {
3179
		$advskew = "advskew " . escapeshellarg($vip['advskew']);
3180
	}
3181

    
3182
	mwexec("/sbin/ifconfig {$realif} vhid " . escapeshellarg($vip['vhid']) .
3183
	    " {$advskew} {$advbase} {$password}");
3184

    
3185
	if (!$maintenancemode_only) {
3186
		if (is_ipaddrv4($vip['subnet'])) {
3187
			mwexec("/sbin/ifconfig {$realif} " .
3188
			    escapeshellarg($vip['subnet']) . "/" .
3189
			    escapeshellarg($vip['subnet_bits']) .
3190
			    " alias vhid " . escapeshellarg($vip['vhid']));
3191
		} elseif (is_ipaddrv6($vip['subnet'])) {
3192
			mwexec("/sbin/ifconfig {$realif} inet6 " .
3193
			    escapeshellarg($vip['subnet']) . " prefixlen " .
3194
			    escapeshellarg($vip['subnet_bits']) .
3195
			    " alias vhid " . escapeshellarg($vip['vhid']));
3196
		}
3197
	}
3198

    
3199
	/* reconfigure stacked IP Aliases after CARP VIP changes, see https://redmine.pfsense.org/issues/12227 */
3200
	if (!platform_booting()) {
3201
		foreach ($config['virtualip']['vip'] as $viface) {
3202
			if (($viface['mode'] == 'ipalias') &&
3203
			    (get_root_interface($viface['interface']) == $vip['interface'])) { 
3204
				interface_vip_bring_down($viface);
3205
				interface_ipalias_configure($viface);
3206
			}
3207
		}
3208
	}
3209

    
3210
	return $realif;
3211
}
3212

    
3213
function interface_wireless_clone($realif, $wlcfg) {
3214
	global $config, $g;
3215
	/*   Check to see if interface has been cloned as of yet.
3216
	 *   If it has not been cloned then go ahead and clone it.
3217
	 */
3218
	$needs_clone = false;
3219
	if (is_array($wlcfg['wireless'])) {
3220
		$wlcfg_mode = $wlcfg['wireless']['mode'];
3221
	} else {
3222
		$wlcfg_mode = $wlcfg['mode'];
3223
	}
3224
	switch ($wlcfg_mode) {
3225
		case "hostap":
3226
			$mode = "wlanmode hostap";
3227
			break;
3228
		case "adhoc":
3229
			$mode = "wlanmode adhoc";
3230
			break;
3231
		default:
3232
			$mode = "";
3233
			break;
3234
	}
3235
	$baseif = interface_get_wireless_base($wlcfg['if']);
3236
	if (does_interface_exist($realif)) {
3237
		exec("/sbin/ifconfig " . escapeshellarg($realif), $output, $ret);
3238
		$ifconfig_str = implode($output);
3239
		if (($wlcfg_mode == "hostap") && (!preg_match("/hostap/si", $ifconfig_str))) {
3240
			log_error(sprintf(gettext("Interface %s changed to hostap mode"), $realif));
3241
			$needs_clone = true;
3242
		}
3243
		if (($wlcfg_mode == "adhoc") && (!preg_match("/adhoc/si", $ifconfig_str))) {
3244
			log_error(sprintf(gettext("Interface %s changed to adhoc mode"), $realif));
3245
			$needs_clone = true;
3246
		}
3247
		if (($wlcfg_mode == "bss") && (preg_match("/hostap|adhoc/si", $ifconfig_str))) {
3248
			log_error(sprintf(gettext("Interface %s changed to infrastructure mode"), $realif));
3249
			$needs_clone = true;
3250
		}
3251
	} else {
3252
		$needs_clone = true;
3253
	}
3254

    
3255
	if ($needs_clone == true) {
3256
		/* remove previous instance if it exists */
3257
		if (does_interface_exist($realif)) {
3258
			pfSense_interface_destroy($realif);
3259

    
3260
			/* Invalidate cache */
3261
			get_interface_arr(true);
3262
		}
3263

    
3264
		log_error(sprintf(gettext("Cloning new wireless interface %s"), $realif));
3265
		// Create the new wlan interface. FreeBSD returns the new interface name.
3266
		// example:  wlan2
3267
		exec("/sbin/ifconfig wlan create wlandev {$baseif} {$mode} bssid 2>&1", $out, $ret);
3268
		if ($ret <> 0) {
3269
			log_error(sprintf(gettext('Failed to clone interface %1$s with error code %2$s, output %3$s'), $baseif, $ret, $out[0]));
3270
			return false;
3271
		}
3272
		$newif = trim($out[0]);
3273
		// Rename the interface to {$parentnic}_wlan{$number}#: EX: ath0_wlan0
3274
		pfSense_interface_rename($newif, $realif);
3275
		file_put_contents("{$g['tmp_path']}/{$realif}_oldmac", get_interface_mac($realif));
3276
	}
3277
	return true;
3278
}
3279

    
3280
function interface_sync_wireless_clones(&$ifcfg, $sync_changes = false) {
3281
	global $config, $g;
3282

    
3283
	$shared_settings = array('standard', 'turbo', 'protmode', 'txpower', 'channel',
3284
				 'diversity', 'txantenna', 'rxantenna', 'distance',
3285
				 'regdomain', 'regcountry', 'reglocation');
3286

    
3287
	if (!is_interface_wireless($ifcfg['if'])) {
3288
		return;
3289
	}
3290

    
3291
	$baseif = interface_get_wireless_base($ifcfg['if']);
3292

    
3293
	// Sync shared settings for assigned clones
3294
	$iflist = get_configured_interface_list(true);
3295
	foreach ($iflist as $if) {
3296
		if ($baseif == interface_get_wireless_base($config['interfaces'][$if]['if']) && $ifcfg['if'] != $config['interfaces'][$if]['if']) {
3297
			if (isset($config['interfaces'][$if]['wireless']['standard']) || $sync_changes) {
3298
				foreach ($shared_settings as $setting) {
3299
					if ($sync_changes) {
3300
						if (isset($ifcfg['wireless'][$setting])) {
3301
							$config['interfaces'][$if]['wireless'][$setting] = $ifcfg['wireless'][$setting];
3302
						} elseif (isset($config['interfaces'][$if]['wireless'][$setting])) {
3303
							unset($config['interfaces'][$if]['wireless'][$setting]);
3304
						}
3305
					} else {
3306
						if (isset($config['interfaces'][$if]['wireless'][$setting])) {
3307
							$ifcfg['wireless'][$setting] = $config['interfaces'][$if]['wireless'][$setting];
3308
						} elseif (isset($ifcfg['wireless'][$setting])) {
3309
							unset($ifcfg['wireless'][$setting]);
3310
						}
3311
					}
3312
				}
3313
				if (!$sync_changes) {
3314
					break;
3315
				}
3316
			}
3317
		}
3318
	}
3319

    
3320
	// Read or write settings at shared area
3321
	if (isset($config['wireless']['interfaces'][$baseif]) && is_array($config['wireless']['interfaces'][$baseif])) {
3322
		foreach ($shared_settings as $setting) {
3323
			if ($sync_changes) {
3324
				if (isset($ifcfg['wireless'][$setting])) {
3325
					$config['wireless']['interfaces'][$baseif][$setting] = $ifcfg['wireless'][$setting];
3326
				} elseif (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3327
					unset($config['wireless']['interfaces'][$baseif][$setting]);
3328
				}
3329
			} elseif (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3330
				if (isset($config['wireless']['interfaces'][$baseif][$setting])) {
3331
					$ifcfg['wireless'][$setting] = $config['wireless']['interfaces'][$baseif][$setting];
3332
				} elseif (isset($ifcfg['wireless'][$setting])) {
3333
					unset($ifcfg['wireless'][$setting]);
3334
				}
3335
			}
3336
		}
3337
	}
3338

    
3339
	// Sync the mode on the clone creation page with the configured mode on the interface
3340
	if (interface_is_wireless_clone($ifcfg['if']) && isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3341
		foreach ($config['wireless']['clone'] as &$clone) {
3342
			if ($clone['cloneif'] == $ifcfg['if']) {
3343
				if ($sync_changes) {
3344
					$clone['mode'] = $ifcfg['wireless']['mode'];
3345
				} else {
3346
					$ifcfg['wireless']['mode'] = $clone['mode'];
3347
				}
3348
				break;
3349
			}
3350
		}
3351
		unset($clone);
3352
	}
3353
}
3354

    
3355
function interface_wireless_configure($if, &$wl, &$wlcfg) {
3356
	global $config, $g;
3357

    
3358
	/*    open up a shell script that will be used to output the commands.
3359
	 *    since wireless is changing a lot, these series of commands are fragile
3360
	 *    and will sometimes need to be verified by a operator by executing the command
3361
	 *    and returning the output of the command to the developers for inspection.  please
3362
	 *    do not change this routine from a shell script to individual exec commands.  -sullrich
3363
	 */
3364

    
3365
	// Remove script file
3366
	unlink_if_exists("{$g['tmp_path']}/{$if}_setup.sh");
3367

    
3368
	// Clone wireless nic if needed.
3369
	interface_wireless_clone($if, $wl);
3370

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

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

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

    
3380
	/* set values for /path/program */
3381
	if (file_exists("/usr/local/sbin/hostapd")) {
3382
		$hostapd = "/usr/local/sbin/hostapd";
3383
	} else {
3384
		$hostapd = "/usr/sbin/hostapd";
3385
	}
3386
	if (file_exists("/usr/local/sbin/wpa_supplicant")) {
3387
		$wpa_supplicant = "/usr/local/sbin/wpa_supplicant";
3388
	} else {
3389
		$wpa_supplicant = "/usr/sbin/wpa_supplicant";
3390
	}
3391
	$ifconfig = "/sbin/ifconfig";
3392
	$sysctl = "/sbin/sysctl";
3393
	$sysctl_args = "-q";
3394
	$killall = "/usr/bin/killall";
3395

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

    
3398
	$wlcmd = array();
3399
	$wl_sysctl = array();
3400
	/* Set a/b/g standard */
3401
	$standard = str_replace(" Turbo", "", $wlcfg['standard']);
3402
	/* skip mode entirely for "auto" */
3403
	if ($wlcfg['standard'] != "auto") {
3404
		$wlcmd[] = "mode " . escapeshellarg($standard);
3405
	}
3406

    
3407
	/* XXX: Disable ampdu for now on mwl when running in 11n mode
3408
	 * to prevent massive packet loss under certain conditions. */
3409
	if (preg_match("/^mwl/i", $if) && ($standard == "11ng" || $standard == "11na")) {
3410
		$wlcmd[] = "-ampdu";
3411
	}
3412

    
3413
	/* Set ssid */
3414
	if ($wlcfg['ssid']) {
3415
		$wlcmd[] = "ssid " .escapeshellarg($wlcfg['ssid']);
3416
	}
3417

    
3418
	/* Set 802.11g protection mode */
3419
	$wlcmd[] = "protmode " . escapeshellarg($wlcfg['protmode']);
3420

    
3421
	/* set wireless channel value */
3422
	if (isset($wlcfg['channel'])) {
3423
		if ($wlcfg['channel'] == "0") {
3424
			$wlcmd[] = "channel any";
3425
		} else {
3426
			if ($wlcfg['channel_width'] != "0") {
3427
				$channel_width = ":" . $wlcfg['channel_width'];
3428
			} else {
3429
				$channel_width = '';
3430
			}
3431
			$wlcmd[] = "channel " . escapeshellarg($wlcfg['channel']) . $channel_width;
3432
		}
3433
	}
3434

    
3435
	/* Set antenna diversity value */
3436
	if (isset($wlcfg['diversity'])) {
3437
		$wl_sysctl[] = "diversity=" . escapeshellarg($wlcfg['diversity']);
3438
	}
3439

    
3440
	/* Set txantenna value */
3441
	if (isset($wlcfg['txantenna'])) {
3442
		$wl_sysctl[] = "txantenna=" . escapeshellarg($wlcfg['txantenna']);
3443
	}
3444

    
3445
	/* Set rxantenna value */
3446
	if (isset($wlcfg['rxantenna'])) {
3447
		$wl_sysctl[] = "rxantenna=" . escapeshellarg($wlcfg['rxantenna']);
3448
	}
3449

    
3450
	/* set Distance value */
3451
	if ($wlcfg['distance']) {
3452
		$distance = escapeshellarg($wlcfg['distance']);
3453
	}
3454

    
3455
	/* Set wireless hostap mode */
3456
	if ($wlcfg['mode'] == "hostap") {
3457
		$wlcmd[] = "mediaopt hostap";
3458
	} else {
3459
		$wlcmd[] = "-mediaopt hostap";
3460
	}
3461

    
3462
	/* Set wireless adhoc mode */
3463
	if ($wlcfg['mode'] == "adhoc") {
3464
		$wlcmd[] = "mediaopt adhoc";
3465
	} else {
3466
		$wlcmd[] = "-mediaopt adhoc";
3467
	}
3468

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

    
3471
	/* handle hide ssid option */
3472
	if (isset($wlcfg['hidessid']['enable'])) {
3473
		$wlcmd[] = "hidessid";
3474
	} else {
3475
		$wlcmd[] = "-hidessid";
3476
	}
3477

    
3478
	/* handle pureg (802.11g) only option */
3479
	if (isset($wlcfg['pureg']['enable'])) {
3480
		$wlcmd[] = "mode 11g pureg";
3481
	} else {
3482
		$wlcmd[] = "-pureg";
3483
	}
3484

    
3485
	/* handle puren (802.11n) only option */
3486
	if (isset($wlcfg['puren']['enable'])) {
3487
		$wlcmd[] = "puren";
3488
	} else {
3489
		$wlcmd[] = "-puren";
3490
	}
3491

    
3492
	/* enable apbridge option */
3493
	if (isset($wlcfg['apbridge']['enable'])) {
3494
		$wlcmd[] = "apbridge";
3495
	} else {
3496
		$wlcmd[] = "-apbridge";
3497
	}
3498

    
3499
	/* handle turbo option */
3500
	if (isset($wlcfg['turbo']['enable'])) {
3501
		$wlcmd[] = "mediaopt turbo";
3502
	} else {
3503
		$wlcmd[] = "-mediaopt turbo";
3504
	}
3505

    
3506
	/* handle txpower setting */
3507
	// or don't. this has issues at the moment.
3508
	/*
3509
	if ($wlcfg['txpower'] <> "" && is_numeric($wlcfg['txpower'])) {
3510
		$wlcmd[] = "txpower " . escapeshellarg($wlcfg['txpower']);
3511
	}*/
3512

    
3513
	/* handle wme option */
3514
	if (isset($wlcfg['wme']['enable'])) {
3515
		$wlcmd[] = "wme";
3516
	} else {
3517
		$wlcmd[] = "-wme";
3518
	}
3519

    
3520
	/* Enable wpa if it's configured. No WEP support anymore. */
3521
	if (isset($wlcfg['wpa']['enable'])) {
3522
		$wlcmd[] = "authmode wpa wepmode off ";
3523
	} else {
3524
		$wlcmd[] = "authmode open wepmode off ";
3525
	}
3526

    
3527
	kill_hostapd($if);
3528
	mwexec(kill_wpasupplicant("{$if}"));
3529

    
3530
	$wpa_supplicant_file = "{$g['varetc_path']}/wpa_supplicant_{$if}.";
3531
	$hostapd_conf = "{$g['varetc_path']}/hostapd_{$if}.conf";
3532

    
3533
	unlink_if_exists("{$wpa_supplicant_file}*");
3534
	unlink_if_exists($hostapd_conf);
3535

    
3536
	/* generate wpa_supplicant/hostap config if wpa is enabled */
3537

    
3538
	switch ($wlcfg['mode']) {
3539
		case 'bss':
3540
			if (isset($wlcfg['wpa']['enable'])) {
3541
				$wpa .= <<<EOD
3542
ctrl_interface={$g['varrun_path']}/wpa_supplicant
3543
ctrl_interface_group=0
3544
ap_scan=1
3545
#fast_reauth=1
3546
network={
3547
ssid="{$wlcfg['ssid']}"
3548
scan_ssid=1
3549
priority=5
3550
key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3551
pairwise={$wlcfg['wpa']['wpa_pairwise']}
3552
group={$wlcfg['wpa']['wpa_pairwise']}
3553

    
3554
EOD;
3555
				if ($wlcfg['wpa']['wpa_key_mgmt'] == 'WPA-EAP') {
3556
					if (($wlcfg['wpa']['wpa_eap_client_mode'] == 'PEAP') ||
3557
					    ($wlcfg['wpa']['wpa_eap_client_mode'] == 'TTLS')) {
3558
						if ($wlcfg['wpa']['wpa_eap_inner_auth'] == 'MSCHAPV2') {
3559
							$wpa .= "phase1=\"peaplabel=0\"\n";
3560
						}
3561
						$wpa .= "phase2=\"auth={$wlcfg['wpa']['wpa_eap_inner_auth']}\"\n";
3562
						$wpa .= "identity=\"{$wlcfg['wpa']['wpa_eap_inner_id']}\"\n";
3563
						$eappass = base64_decode($wlcfg['wpa']['wpa_eap_inner_password']);
3564
						$wpa .= "password=\"{$eappass}\"\n";
3565
					}
3566
					if (strstr($wlcfg['wpa']['wpa_eap_client_mode'], 'TLS')) { 
3567
						$cert = lookup_cert($wlcfg['wpa']['wpa_eap_cert']);
3568
						@file_put_contents($wpa_supplicant_file . "crt", base64_decode($cert['crt']) . "\n" .
3569
						    ca_chain($cert)); 
3570
						@file_put_contents($wpa_supplicant_file . "key", base64_decode($cert['prv'])); 
3571
						@chmod($wpa_supplicant_crt, 0600);
3572
						@chmod($wpa_supplicant_key, 0600);
3573
						$wpa .= "client_cert=\"{$wpa_supplicant_crt}\"\n";
3574
						$wpa .= "private_key=\"{$wpa_supplicant_key}\"\n";
3575
					}
3576
					$ca = lookup_ca($wlcfg['wpa']['wpa_eap_ca']);
3577
					@file_put_contents($wpa_supplicant_file . "ca", base64_decode($ca['crt']) . "\n" .
3578
					    ca_chain($ca)); 
3579
					$wpa .= "ca_cert=\"{$wpa_supplicant_ca}\"\n";
3580
					$wpa .= "eap={$wlcfg['wpa']['wpa_eap_client_mode']}\n";
3581
				} else {
3582
					$wpa .= "psk=\"{$wlcfg['wpa']['passphrase']}\"\n";
3583
				}
3584
				$wpa .= "}\n";
3585

    
3586
				@file_put_contents($wpa_supplicant_file . "conf", $wpa);
3587
				unset($wpa);
3588
			}
3589
			break;
3590
		case 'hostap':
3591
			if (!empty($wlcfg['wpa']['passphrase'])) {
3592
				$wpa_passphrase = "wpa_passphrase={$wlcfg['wpa']['passphrase']}\n";
3593
			} else {
3594
				$wpa_passphrase = "";
3595
			}
3596
			if (isset($wlcfg['wpa']['enable'])) {
3597
				$wpa .= <<<EOD
3598
interface={$if}
3599
driver=bsd
3600
logger_syslog=-1
3601
logger_syslog_level=0
3602
logger_stdout=-1
3603
logger_stdout_level=0
3604
dump_file={$g['tmp_path']}/hostapd_{$if}.dump
3605
ctrl_interface={$g['varrun_path']}/hostapd
3606
ctrl_interface_group=wheel
3607
#accept_mac_file={$g['tmp_path']}/hostapd_{$if}.accept
3608
#deny_mac_file={$g['tmp_path']}/hostapd_{$if}.deny
3609
#macaddr_acl={$wlcfg['wpa']['macaddr_acl']}
3610
ssid={$wlcfg['ssid']}
3611
debug={$wlcfg['wpa']['debug_mode']}
3612
wpa={$wlcfg['wpa']['wpa_mode']}
3613
wpa_key_mgmt={$wlcfg['wpa']['wpa_key_mgmt']}
3614
wpa_pairwise={$wlcfg['wpa']['wpa_pairwise']}
3615
wpa_group_rekey={$wlcfg['wpa']['wpa_group_rekey']}
3616
wpa_gmk_rekey={$wlcfg['wpa']['wpa_gmk_rekey']}
3617
wpa_strict_rekey={$wlcfg['wpa']['wpa_strict_rekey']}
3618
{$wpa_passphrase}
3619

    
3620
EOD;
3621

    
3622
				if (isset($wlcfg['wpa']['rsn_preauth'])) {
3623
					$wpa .= <<<EOD
3624
# Enable the next lines for preauth when roaming. Interface = wired or wireless interface talking to the AP to roam from/to
3625
rsn_preauth=1
3626
rsn_preauth_interfaces={$if}
3627

    
3628
EOD;
3629
				}
3630
				if (is_array($wlcfg['wpa']['ieee8021x']) && isset($wlcfg['wpa']['ieee8021x']['enable'])) {
3631
					$wpa .= "ieee8021x=1\n";
3632

    
3633
					if (!empty($wlcfg['auth_server_addr']) && !empty($wlcfg['auth_server_shared_secret'])) {
3634
						$auth_server_port = "1812";
3635
						if (!empty($wlcfg['auth_server_port']) && is_numeric($wlcfg['auth_server_port'])) {
3636
							$auth_server_port = intval($wlcfg['auth_server_port']);
3637
						}
3638
						$wpa .= <<<EOD
3639

    
3640
auth_server_addr={$wlcfg['auth_server_addr']}
3641
auth_server_port={$auth_server_port}
3642
auth_server_shared_secret={$wlcfg['auth_server_shared_secret']}
3643

    
3644
EOD;
3645
						if (!empty($wlcfg['auth_server_addr2']) && !empty($wlcfg['auth_server_shared_secret2'])) {
3646
							$auth_server_port2 = "1812";
3647
							if (!empty($wlcfg['auth_server_port2']) && is_numeric($wlcfg['auth_server_port2'])) {
3648
								$auth_server_port2 = intval($wlcfg['auth_server_port2']);
3649
							}
3650

    
3651
							$wpa .= <<<EOD
3652
auth_server_addr={$wlcfg['auth_server_addr2']}
3653
auth_server_port={$auth_server_port2}
3654
auth_server_shared_secret={$wlcfg['auth_server_shared_secret2']}
3655

    
3656
EOD;
3657
						}
3658
					}
3659
				}
3660

    
3661
				@file_put_contents($hostapd_conf, $wpa);
3662
				unset($wpa);
3663
			}
3664
			break;
3665
	}
3666

    
3667
	/*
3668
	 *    all variables are set, lets start up everything
3669
	 */
3670

    
3671
	$baseif = interface_get_wireless_base($if);
3672
	preg_match("/^(.*?)([0-9]*)$/", $baseif, $baseif_split);
3673
	$wl_sysctl_prefix = 'dev.' . $baseif_split[1] . '.' . $baseif_split[2];
3674

    
3675
	/* set sysctls for the wireless interface */
3676
	if (!empty($wl_sysctl)) {
3677
		fwrite($fd_set, "# sysctls for {$baseif}\n");
3678
		foreach ($wl_sysctl as $wl_sysctl_line) {
3679
			fwrite($fd_set, "{$sysctl} ${sysctl_args} {$wl_sysctl_prefix}.{$wl_sysctl_line}\n");
3680
		}
3681
	}
3682

    
3683
	/* set ack timers according to users preference (if he/she has any) */
3684
	if ($distance) {
3685
		fwrite($fd_set, "# Enable ATH distance settings\n");
3686
		fwrite($fd_set, "/usr/local/sbin/athctrl.sh -i {$baseif} -d {$distance}\n");
3687
	}
3688

    
3689
	if (isset($wlcfg['wpa']['enable'])) {
3690
		if ($wlcfg['mode'] == "bss") {
3691
			fwrite($fd_set, "{$wpa_supplicant} -B -i {$if} -c {$g['varetc_path']}/wpa_supplicant_{$if}.conf\n");
3692
		}
3693
		if ($wlcfg['mode'] == "hostap") {
3694
			/* add line to script to restore old mac to make hostapd happy */
3695
			if (file_exists("{$g['tmp_path']}/{$if}_oldmac")) {
3696
				$if_oldmac = file_get_contents("{$g['tmp_path']}/{$if}_oldmac");
3697
				$if_curmac = get_interface_mac($if);
3698
				if ($if_curmac != $if_oldmac && is_macaddr($if_oldmac)) {
3699
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3700
						" link " . escapeshellarg($if_oldmac) . "\n");
3701
				}
3702
			}
3703

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

    
3706
			/* add line to script to restore spoofed mac after running hostapd */
3707
			if ($wl['spoofmac']) {
3708
				$if_curmac = get_interface_mac($if);
3709
				if ($wl['spoofmac'] != $if_curmac && is_macaddr($wl['spoofmac'])) {
3710
					fwrite($fd_set, "{$ifconfig} " . escapeshellarg($if) .
3711
						" link " . escapeshellarg($wl['spoofmac']) . "\n");
3712
				}
3713
			}
3714
		}
3715
	}
3716

    
3717
	fclose($fd_set);
3718

    
3719
	/* Making sure regulatory settings have actually changed
3720
	 * before applying, because changing them requires bringing
3721
	 * down all wireless networks on the interface. */
3722
	exec("{$ifconfig} " . escapeshellarg($if), $output);
3723
	$ifconfig_str = implode($output);
3724
	unset($output);
3725
	$reg_changing = false;
3726

    
3727
	/* special case for the debug country code */
3728
	if ($wlcfg['regcountry'] == 'DEBUG' && !preg_match("/\sregdomain\s+DEBUG\s/si", $ifconfig_str)) {
3729
		$reg_changing = true;
3730
	} elseif ($wlcfg['regdomain'] && !preg_match("/\sregdomain\s+{$wlcfg['regdomain']}\s/si", $ifconfig_str)) {
3731
		$reg_changing = true;
3732
	} elseif ($wlcfg['regcountry'] && !preg_match("/\scountry\s+{$wlcfg['regcountry']}\s/si", $ifconfig_str)) {
3733
		$reg_changing = true;
3734
	} elseif ($wlcfg['reglocation'] == 'anywhere' && preg_match("/\s(indoor|outdoor)\s/si", $ifconfig_str)) {
3735
		$reg_changing = true;
3736
	} elseif ($wlcfg['reglocation'] && $wlcfg['reglocation'] != 'anywhere' && !preg_match("/\s{$wlcfg['reglocation']}\s/si", $ifconfig_str)) {
3737
		$reg_changing = true;
3738
	}
3739

    
3740
	if ($reg_changing) {
3741
		/* set regulatory domain */
3742
		if ($wlcfg['regdomain']) {
3743
			$wlregcmd[] = "regdomain " . escapeshellarg($wlcfg['regdomain']);
3744
		}
3745

    
3746
		/* set country */
3747
		if ($wlcfg['regcountry']) {
3748
			$wlregcmd[] = "country " . escapeshellarg($wlcfg['regcountry']);
3749
		}
3750

    
3751
		/* set location */
3752
		if ($wlcfg['reglocation']) {
3753
			$wlregcmd[] = escapeshellarg($wlcfg['reglocation']);
3754
		}
3755

    
3756
		$wlregcmd_args = implode(" ", $wlregcmd);
3757

    
3758
		/* build a complete list of the wireless clones for this interface */
3759
		$clone_list = array();
3760
		if (does_interface_exist(interface_get_wireless_clone($baseif))) {
3761
			$clone_list[] = interface_get_wireless_clone($baseif);
3762
		}
3763
		if (isset($config['wireless']['clone']) && is_array($config['wireless']['clone'])) {
3764
			foreach ($config['wireless']['clone'] as $clone) {
3765
				if ($clone['if'] == $baseif) {
3766
					$clone_list[] = $clone['cloneif'];
3767
				}
3768
			}
3769
		}
3770

    
3771
		/* find which clones are up and bring them down */
3772
		$clones_up = array();
3773
		foreach ($clone_list as $clone_if) {
3774
			$clone_status = pfSense_get_interface_addresses($clone_if);
3775
			if ($clone_status['status'] == 'up') {
3776
				$clones_up[] = $clone_if;
3777
				mwexec("{$ifconfig} " . escapeshellarg($clone_if) . " down");
3778
			}
3779
		}
3780

    
3781
		/* apply the regulatory settings */
3782
		mwexec("{$ifconfig} " . escapeshellarg($if) . " {$wlregcmd_args}");
3783
		fwrite($wlan_setup_log, "$ifconfig" . escapeshellarg($if) . "$wlregcmd_args \n");
3784

    
3785
		/* bring the clones back up that were previously up */
3786
		foreach ($clones_up as $clone_if) {
3787
			interfaces_bring_up($clone_if);
3788

    
3789
			/*
3790
			 * Rerun the setup script for the interface if it isn't this interface, the interface
3791
			 * is in infrastructure mode, and WPA is enabled.
3792
			 * This can be removed if wpa_supplicant stops dying when you bring the interface down.
3793
			 */
3794
			if ($clone_if != $if) {
3795
				$friendly_if = convert_real_interface_to_friendly_interface_name($clone_if);
3796
				if ((!empty($friendly_if)) &&
3797
				    ($config['interfaces'][$friendly_if]['wireless']['mode'] == "bss") &&
3798
				    (isset($config['interfaces'][$friendly_if]['wireless']['wpa']['enable']))) {
3799
					mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($clone_if) . "_setup.sh");
3800
				}
3801
			}
3802
		}
3803
	}
3804

    
3805
	/* The mode must be specified in a separate command before ifconfig
3806
	 * will allow the mode and channel at the same time in the next.
3807
	 * Only do this for AP mode as this breaks client mode (PR 198680).
3808
	 */
3809
	if ($wlcfg['mode'] == "hostap") {
3810
		mwexec("/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard));
3811
		fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " mode " . escapeshellarg($standard) . "\n");
3812
	}
3813

    
3814
	/* configure wireless */
3815
	$wlcmd_args = implode(" ", $wlcmd);
3816
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " " . $wlcmd_args);
3817
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " " . "$wlcmd_args \n");
3818
	/* Bring the interface up only after setting up all the other parameters. */
3819
	mwexec("/sbin/ifconfig " . escapeshellarg($if) . " up");
3820
	fwrite($wlan_setup_log, "/sbin/ifconfig " . escapeshellarg($if) . " up\n");
3821
	fclose($wlan_setup_log);
3822

    
3823
	unset($wlcmd_args, $wlcmd);
3824

    
3825

    
3826
	sleep(1);
3827
	/* execute hostapd and wpa_supplicant if required in shell */
3828
	mwexec("/bin/sh {$g['tmp_path']}/" . escapeshellarg($if) . "_setup.sh");
3829

    
3830
	return 0;
3831

    
3832
}
3833

    
3834
function kill_hostapd($interface) {
3835
	global $g;
3836

    
3837
	if (isvalidpid("{$g['varrun_path']}/hostapd_{$interface}.pid")) {
3838
		return killbypid("{$g['varrun_path']}/hostapd_{$interface}.pid");
3839
	}
3840
}
3841

    
3842
function kill_wpasupplicant($interface) {
3843
	return "/bin/pkill -f \"wpa_supplicant .*{$interface}\\.conf\"\n";
3844
}
3845

    
3846
function find_dhclient_process($interface) {
3847
	if ($interface) {
3848
		$pid = `/bin/pgrep -axf "dhclient: {$interface}"`;
3849
	} else {
3850
		$pid = 0;
3851
	}
3852

    
3853
	return intval($pid);
3854
}
3855

    
3856
function kill_dhclient_process($interface) {
3857
	if (empty($interface) || !does_interface_exist($interface)) {
3858
		return;
3859
	}
3860

    
3861
	$i = 0;
3862
	while ((($pid = find_dhclient_process($interface)) != 0) && ($i < 3)) {
3863
		/* 3rd time make it die for sure */
3864
		$sig = ($i == 2 ? SIGKILL : SIGTERM);
3865
		posix_kill($pid, $sig);
3866
		sleep(1);
3867
		$i++;
3868
	}
3869
	unset($i);
3870
}
3871

    
3872
function find_dhcp6c_process() {
3873
	global $g;
3874

    
3875
	if (isvalidpid("{$g['varrun_path']}/dhcp6c.pid")) {
3876
		$pid = trim(file_get_contents("{$g['varrun_path']}/dhcp6c.pid"), " \n");
3877
	} else {
3878
		return(false);
3879
	}
3880

    
3881
	return intval($pid);
3882
}
3883

    
3884
function kill_dhcp6client_process($force, $release = false) {
3885
	global $g;
3886

    
3887
	$i = 0;
3888

    
3889
	/*
3890
	Beware of the following: Reason, the interface may be down, but
3891
	dhcp6c may still be running, it just complains it cannot send
3892
	and carries on. Commented out as will stop the call to kill.
3893

    
3894
	if (empty($interface) || !does_interface_exist($interface)) {
3895
		return;
3896
	}
3897
	*/
3898

    
3899
	/*********** Notes on signals for dhcp6c and this function *************
3900

    
3901
	If we have Taken the WAN interface down, then dhcp6c sits there sending
3902
	a release and waiting for the response that never comes.
3903
	So we need to tell it that the interface is down and to just die quickly
3904
	otherwise a new client may launch and we have duplicate proceses.
3905
	In this case use SIGUSR1.
3906

    
3907
	If we want to exit normally obeying the no release flag then use SIGTERM.
3908
	If we want to exit with a release overiding the no release flag then
3909
	use SIGUSR2.
3910

    
3911
	If $Force is true it will use SIGUSR1, thus forcing dhcp6c to
3912
	exit quickly without sending release signals.
3913

    
3914
	If $Force is set to false and $release is also set to false dhcp6c will
3915
	follow the no-release flag.
3916

    
3917
	If $Force is set to false and $release is true then dhcp6c will send a
3918
	release regardless of the no-release flag.
3919
	***********************************************************************/
3920

    
3921
	if ($force == true) {
3922
		$psig=SIGUSR1;
3923
	} elseif ($release == false) {
3924
		$psig=SIGTERM;
3925
	} else {
3926
		$psig=SIGUSR2;
3927
	}
3928

    
3929
	while ((($pid = find_dhcp6c_process()) != 0) && ($i < 3)) {
3930
		/* 3rd time make it die for sure */
3931
		$sig = ($i == 2 ? SIGKILL : $psig);
3932
		posix_kill($pid, $sig);
3933
		sleep(1);
3934
		$i++;
3935
	}
3936
	/* Clear the RTSOLD script created lock & tidy up */
3937
	unlink_if_exists("/tmp/dhcp6c_lock");
3938
	unlink_if_exists("{$g['varrun_path']}/dhcp6c.pid"); // just in case!
3939
}
3940
function reset_dhcp6client_process() {
3941

    
3942
	$pid = find_dhcp6c_process();
3943

    
3944
	if($pid != 0) {
3945
		posix_kill($pid, SIGHUP);
3946
	}
3947
}
3948

    
3949
function run_dhcp6client_process($interfaces, $debugOption, $noreleaseOption) {
3950
	global $g;
3951

    
3952
	/*
3953
	 * Only run this if the lock does not exist. In theory the lock being
3954
	 * there in this mode means the user has selected dhcp6withoutRA while
3955
	 * a session is active in the other mode.
3956
	 *
3957
	 * It should not happen as the process should have been killed and the
3958
	 * lock deleted.
3959
	 */
3960

    
3961
	if (!file_exists("/tmp/dhcp6c_lock")) {
3962
		kill_dhcp6client_process(true);
3963
		/* Lock it to avoid multiple runs */
3964
		touch("/tmp/dhcp6c_lock");
3965
		mwexec("/usr/local/sbin/dhcp6c {$debugOptions} " .
3966
		    "{$noreleaseOption} " .
3967
		    "-c {$g['varetc_path']}/dhcp6c.conf " .
3968
		    "-p {$g['varrun_path']}/dhcp6c.pid " .
3969
		    implode(' ', $interfaces));
3970
		log_error(sprintf(gettext(
3971
		    "Starting DHCP6 client for interfaces %s in DHCP6 without RA mode"),
3972
		    implode(',', $interfaces)));
3973
	}
3974
}
3975

    
3976
function interface_virtual_create($interface, $gateways_status = false) {
3977
	global $config;
3978

    
3979
	/* Fetch gateway status if not passed */
3980
	if (!is_array($gateways_status)) {
3981
		$gateways_status = return_gateways_status(true);
3982
	}
3983

    
3984
	if (interface_is_vlan($interface) != NULL) {
3985
		interface_vlan_configure(interface_is_vlan($interface));
3986
	} elseif (substr($interface, 0, 3) == "gre") {
3987
		interfaces_tunnel_configure(0, $interface, 'gre');
3988
	} elseif (substr($interface, 0, 3) == "gif") {
3989
		interfaces_tunnel_configure(0, $interface, 'gif');
3990
	} elseif (substr($interface, 0, 5) == "ovpns") {
3991
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-server'])) {
3992
			foreach ($config['openvpn']['openvpn-server'] as $server) {
3993
				if ($interface == "ovpns{$server['vpnid']}") {
3994
					if (!function_exists('openvpn_resync')) {
3995
						require_once('openvpn.inc');
3996
					}
3997
					log_error(sprintf(gettext("OpenVPN: Resync server %s"), $server['description']));
3998
					openvpn_resync('server', $server);
3999
				}
4000
			}
4001
			unset($server);
4002
		}
4003
	} elseif (substr($interface, 0, 5) == "ovpnc") {
4004
		if (is_array($config['openvpn']) && is_array($config['openvpn']['openvpn-client'])) {
4005
			foreach ($config['openvpn']['openvpn-client'] as $client) {
4006
				if ($interface == "ovpnc{$client['vpnid']}") {
4007
					if (!function_exists('openvpn_resync')) {
4008
						require_once('openvpn.inc');
4009
					}
4010
					log_error(sprintf(gettext("OpenVPN: Resync client %s"), $client['description']));
4011
					openvpn_resync('client', $client);
4012
				}
4013
			}
4014
			unset($client);
4015
		}
4016
	} elseif (substr($interface, 0, 5) == "ipsec") {
4017
		if (is_array($config['ipsec']) && is_array($config['ipsec']['phase1']) && is_array($config['ipsec']['phase2'])) {
4018
			foreach ($config['ipsec']['phase1'] as $ph1ent) {
4019
				if ($ph1ent['disabled']) {
4020
					continue;
4021
				}
4022
				interface_ipsec_vti_configure($ph1ent, $gateways_status);
4023
			}
4024
		}
4025
	} elseif (substr($interface, 0, 4) == "lagg") {
4026
		interfaces_lagg_configure($interface);
4027
	} elseif (substr($interface, 0, 6) == "bridge") {
4028
		interfaces_bridge_configure(0, $interface);
4029
	}
4030
}
4031

    
4032
function interface_vlan_mtu_configured($iface) {
4033
	global $config;
4034

    
4035
	$mtu = 0;
4036
	if (is_array($config['vlans']) && is_array($config['vlans']['vlan'])) {
4037
		foreach ($config['vlans']['vlan'] as $vlan) {
4038

    
4039
			if ($vlan['vlanif'] != $iface)
4040
				continue;
4041

    
4042
			$assignedport = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
4043
			$parentinf = convert_real_interface_to_friendly_interface_name($vlan['if']);
4044
			if (!empty($assignedport) && !empty($config['interfaces'][$assignedport]['mtu'])) {
4045
				/* VLAN MTU */
4046
				$mtu = $config['interfaces'][$assignedport]['mtu'];
4047
			} elseif (!empty($config['interfaces'][$parentinf]['mtu'])) {
4048
				/* Parent MTU */
4049
				$mtu = $config['interfaces'][$parentinf]['mtu'];
4050
			}
4051
		}
4052
	}
4053

    
4054
	return $mtu;
4055
}
4056

    
4057
function interface_mtu_wanted_for_pppoe($realif) {
4058
	global $config;
4059

    
4060
	if (!is_array($config['ppps']) || !is_array($config['ppps']['ppp']))
4061
		return 0;
4062

    
4063
	$mtu = 0;
4064
	foreach ($config['ppps']['ppp'] as $ppp) {
4065
		if ($ppp['type'] != "pppoe") {
4066
			continue;
4067
		}
4068

    
4069
		$mtus = array();
4070
		if (!empty($ppp['mtu'])) {
4071
			$mtus = explode(',', $ppp['mtu']);
4072
		}
4073
		$ports = explode(',', $ppp['ports']);
4074

    
4075
		foreach ($ports as $pid => $port) {
4076
			$parentifa = get_parent_interface($port);
4077
			$parentif = $parentifa[0];
4078
			if ($parentif != $realif)
4079
				continue;
4080

    
4081
			// there is an MTU configured on the port in question
4082
			if (!empty($mtus[$pid])) {
4083
				$mtu = intval($mtus[$pid]) + 8;
4084
			// or use the MTU configured on the interface ...
4085
			} elseif (is_array($config['interfaces'])) {
4086
				foreach ($config['interfaces'] as $interface) {
4087
					if ($interface['if'] == $ppp['if'] &&
4088
					    !empty($interface['mtu'])) {
4089
						$mtu = intval($interface['mtu']) + 8;
4090
						break;
4091
					}
4092
				}
4093
			}
4094
		}
4095
	}
4096

    
4097
	return $mtu;
4098
}
4099

    
4100
function interface_configure($interface = "wan", $reloadall = false, $linkupevent = false) {
4101
	global $config, $g;
4102
	global $interface_sn_arr_cache, $interface_ip_arr_cache;
4103
	global $interface_snv6_arr_cache, $interface_ipv6_arr_cache;
4104

    
4105
	$wancfg = $config['interfaces'][$interface];
4106

    
4107
	if (!isset($wancfg['enable'])) {
4108
		return;
4109
	}
4110

    
4111
	$realif = get_real_interface($interface);
4112
	$realhwif_array = get_parent_interface($interface);
4113
	// Need code to handle MLPPP if we ever use $realhwif for MLPPP handling
4114
	$realhwif = $realhwif_array[0];
4115

    
4116
	$mac_if_cfg = $wancfg;
4117
	if (interface_is_vlan($realif)) {
4118
		$mac_if = convert_real_interface_to_friendly_interface_name(
4119
		    $realhwif);
4120
		if (is_array($config['interfaces'][$mac_if])) {
4121
			$mac_if_cfg = $config['interfaces'][$mac_if];
4122
		} else {
4123
			$mac_if = $interface;
4124
		}
4125
	}
4126

    
4127
	if (!platform_booting() && (substr($realif, 0, 4) != "ovpn") && (substr($realif, 0, 5) != "ipsec")) {
4128
		/* remove all IPv4 and IPv6 addresses */
4129
		$tmpifaces = pfSense_getall_interface_addresses($realif);
4130
		if (is_array($tmpifaces)) {
4131
			foreach ($tmpifaces as $tmpiface) {
4132
				if (is_ipaddrv6($tmpiface) || is_subnetv6($tmpiface)) {
4133
					if (!is_linklocal($tmpiface)) {
4134
						mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$tmpiface} delete");
4135
					}
4136
				} elseif (strstr($tmpiface, "fe80::1:1")) {
4137
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 fe80::1:1 -alias");
4138
				} else {
4139
					if (is_subnetv4($tmpiface)) {
4140
						$tmpip = explode('/', $tmpiface);
4141
						$tmpip = $tmpip[0];
4142
					} else {
4143
						$tmpip = $tmpiface;
4144
					}
4145
					pfSense_interface_deladdress($realif, $tmpip);
4146
				}
4147
			}
4148
		}
4149

    
4150
		/* only bring down the interface when both v4 and v6 are set to NONE */
4151
		if (empty($wancfg['ipaddr']) && empty($wancfg['ipaddrv6'])) {
4152
			interface_bring_down($interface);
4153
		}
4154
	}
4155

    
4156
	$interface_to_check = $realif;
4157
	if (interface_isppp_type($interface)) {
4158
		$interface_to_check = $realhwif;
4159
	}
4160

    
4161
	/* Need to check that the interface exists or not in the case where its coming back from disabled state see #3270 */
4162
	if (!platform_booting() && (in_array(substr($realif, 0, 3), array("gre", "gif")) ||
4163
	    !does_interface_exist($interface_to_check))) {
4164
		interface_virtual_create($interface_to_check);
4165
	}
4166

    
4167
	/* Disable Accepting router advertisements unless specifically requested */
4168
	if ($g['debug']) {
4169
		log_error(sprintf(gettext("Deny router advertisements for interface %s"), $interface));
4170
	}
4171
	if (isset($wancfg['dhcp6usev4iface']) || $wancfg['ipaddr']==='ppp')
4172
	{
4173
		mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 -accept_rtadv", true);
4174
	}
4175
	/* wireless configuration? */
4176
	if (is_array($wancfg['wireless']) && !$linkupevent) {
4177
		interface_wireless_configure($realif, $wancfg, $wancfg['wireless']);
4178
	}
4179

    
4180
	$current_mac = get_interface_mac($realhwif);
4181
	$vendor_mac = get_interface_vendor_mac($realhwif);
4182

    
4183
	if ($current_mac != "ff:ff:ff:ff:ff:ff") {
4184
		$mac_addr = $mac_if_cfg['spoofmac'] ?: $vendor_mac;
4185

    
4186
		interface_set_macaddr($realhwif, $mac_addr);
4187
	} else {
4188
		/*
4189
		 * this is not a valid mac address.  generate a
4190
		 * temporary mac address so the machine can get online.
4191
		 */
4192
		echo gettext("Generating new MAC address.");
4193
		$random_mac = generate_random_mac_address();
4194
		interface_set_macaddr($realhwif, $random_mac);
4195
		$config['interfaces'][$mac_if]['spoofmac'] = $random_mac;
4196
		write_config(sprintf(gettext('The invalid MAC address ' .
4197
		    '(ff:ff:ff:ff:ff:ff) on interface %1$s has been ' .
4198
		    'automatically replaced with %2$s'), $mac_if, $random_mac));
4199
		file_notice("MAC Address altered", sprintf(gettext('The ' .
4200
		    'invalid MAC address (ff:ff:ff:ff:ff:ff) on interface ' .
4201
		    '%1$s has been automatically replaced with %2$s'), $mac_if,
4202
		    $random_mac), "Interfaces");
4203
	}
4204

    
4205
	/* media */
4206
	if ($wancfg['media'] || $wancfg['mediaopt']) {
4207
		$cmd = "/sbin/ifconfig " . escapeshellarg($realhwif);
4208
		if ($wancfg['media']) {
4209
			$cmd .= " media " . escapeshellarg($wancfg['media']);
4210
		}
4211
		if ($wancfg['mediaopt']) {
4212
			$cmd .= " mediaopt " . escapeshellarg($wancfg['mediaopt']);
4213
		}
4214
		mwexec($cmd);
4215
	}
4216

    
4217
	/* Apply hw offloading policies as configured */
4218
	enable_hardware_offloading($interface);
4219

    
4220
	/* invalidate interface/ip/sn cache */
4221
	get_interface_arr(true);
4222
	unset($interface_ip_arr_cache[$realif]);
4223
	unset($interface_sn_arr_cache[$realif]);
4224
	unset($interface_ipv6_arr_cache[$realif]);
4225
	unset($interface_snv6_arr_cache[$realif]);
4226

    
4227
	$tunnelif = substr($realif, 0, 3);
4228

    
4229
	$mtuif = $realif;
4230
	$mtuhwif = $realhwif;
4231

    
4232
	/* adjust MTU of parent interface of PPPoE interface if this does not violate explicit configuration */
4233
	if (interface_isppp_type($interface)) {
4234
		$mtuif = $realhwif;
4235
		$mtuhwif_array = get_parent_interface($mtuif);
4236
		$mtuhwif = $mtuhwif_array[0];
4237
	}
4238

    
4239
	$wantedmtu = 0;
4240
	if (is_array($config['interfaces'])) {
4241
		foreach ($config['interfaces'] as $tmpinterface) {
4242
			if ($tmpinterface['if'] == $mtuif && !empty($tmpinterface['mtu'])) {
4243
				$wantedmtu = $tmpinterface['mtu'];
4244
				break;
4245
			}
4246
		}
4247
	}
4248

    
4249
	/* MTU is not specified for interface, try the pppoe settings. */
4250
	if ($wantedmtu == 0) {
4251
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuif);
4252
	}
4253
	if (($wantedmtu == 0) && (interface_is_vlan($mtuif) != NULL) && interface_isppp_type($interface)) {
4254
		$wantedmtu = interface_mtu_wanted_for_pppoe($mtuhwif);
4255
	}
4256
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gre')) {
4257
		/* set MTU to 1400 for GRE over IPsec */
4258
		if (is_greipsec($mtuif)) {
4259
			$wantedmtu = 1400;
4260
		} else {
4261
			$wantedmtu = 1476;
4262
		}
4263
	}
4264
	if (($wantedmtu == 0) && interface_is_type($mtuif, 'gif')) {
4265
		$wantedmtu = 1280;
4266
	}
4267

    
4268
	/* Set the MTU to 1500 if no explicit MTU configured. */
4269
	if ($wantedmtu == 0) {
4270
		$wantedmtu = 1500; /* Default */
4271
	}
4272

    
4273
	if (interface_is_vlan($mtuif) != NULL) {
4274
		$assignedparent = convert_real_interface_to_friendly_interface_name($mtuhwif);
4275
		if (!empty($assignedparent) && !empty($config['interfaces'][$assignedparent]['mtu'])) {
4276
			$parentmtu = $config['interfaces'][$assignedparent]['mtu'];
4277
			if ($wancfg['mtu'] > $parentmtu) {
4278
				log_error(sprintf(gettext('There is a conflict on MTU between parent %1$s and VLAN(%2$s)'), $mtuhwif, $mtuif));
4279
			}
4280
		}
4281

    
4282
		$configuredmtu = interface_vlan_mtu_configured($mtuif);
4283

    
4284
		if ($configuredmtu != 0 && $configuredmtu > $parentmtu)
4285
			$configuredmtu = $parentmtu;
4286
		if ($configuredmtu != 0)
4287
			$mtu = $configuredmtu;
4288
		else
4289
			$mtu = $wantedmtu;
4290

    
4291
		/* Set the parent MTU. */
4292
		if (get_interface_mtu($mtuhwif) < $mtu)
4293
			set_interface_mtu($mtuhwif, $mtu);
4294
		/* Set the VLAN MTU. */
4295
		if (get_interface_mtu($mtuif) != $mtu)
4296
			set_interface_mtu($mtuif, $mtu);
4297
	} elseif (substr($mtuif, 0, 4) == 'lagg') {
4298
		/* LAGG interface must be destroyed and re-created to change MTU */
4299
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4300
			if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
4301
				foreach ($config['laggs']['lagg'] as $lagg) {
4302
					if ($lagg['laggif'] == $mtuif) {
4303
						interface_lagg_configure($lagg);
4304
						break;
4305
					}
4306
				}
4307
			}
4308
		}
4309
	} else {
4310
		if ($wantedmtu != get_interface_mtu($mtuif)) {
4311
			pfSense_interface_mtu($mtuif, $wantedmtu);
4312
			set_ipv6routes_mtu($mtuif, $wantedmtu);
4313
		}
4314
	}
4315
	/* XXX: What about gre/gif/.. ? */
4316

    
4317
	if (does_interface_exist($wancfg['if'])) {
4318
		interfaces_bring_up($wancfg['if']);
4319
	}
4320

    
4321
	switch ($wancfg['ipaddr']) {
4322
		case 'dhcp':
4323
			interface_dhcp_configure($interface);
4324
			break;
4325
		case 'pppoe':
4326
		case 'l2tp':
4327
		case 'pptp':
4328
		case 'ppp':
4329
			interface_ppps_configure($interface);
4330
			break;
4331
		default:
4332
			/* XXX: Kludge for now related to #3280 */
4333
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
4334
				if (is_ipaddrv4($wancfg['ipaddr']) && $wancfg['subnet'] <> "") {
4335
					pfSense_interface_setaddress($realif, "{$wancfg['ipaddr']}/{$wancfg['subnet']}");
4336
				}
4337
			}
4338
			break;
4339
	}
4340

    
4341
	switch ($wancfg['ipaddrv6']) {
4342
		case 'slaac':
4343
		case 'dhcp6':
4344
			// N.B. PPP connections using PPP as the IPv6 parent interface are excluded because the ppp-ipv6 script
4345
			// calls interface_dhcpv6_configure() for these connections after IPv6CP is up, whilst rc.newwanip
4346
			// handles all non-PPP connections with 'dhcp6usev4iface' set
4347
			log_error(gettext("calling interface_dhcpv6_configure."));
4348
			if ((($wancfg['ipaddrv6'] == 'dhcp6') && !isset($wancfg['dhcp6usev4iface'])) ||
4349
			    (($wancfg['ipaddrv6'] == 'slaac') && !isset($wancfg['slaacusev4iface'])) ||
4350
			    !interface_isppp_type($interface)) {
4351
				interface_dhcpv6_configure($interface, $wancfg);
4352
			}
4353
			break;
4354
		case '6rd':
4355
			interface_6rd_configure($interface, $wancfg);
4356
			break;
4357
		case '6to4':
4358
			interface_6to4_configure($interface, $wancfg);
4359
			break;
4360
		case 'track6':
4361
			interface_track6_configure($interface, $wancfg, $linkupevent);
4362
			break;
4363
		default:
4364
			/* XXX: Kludge for now related to #3280 */
4365
			if (!in_array($tunnelif, array("gif", "gre", "ovp", "ips"))) {
4366
				if (is_ipaddrv6($wancfg['ipaddrv6']) && $wancfg['subnetv6'] <> "") {
4367
					//pfSense_interface_setaddress($realif, "{$wancfg['ipaddrv6']}/{$wancfg['subnetv6']}");
4368
					// FIXME: Add IPv6 Support to the pfSense module
4369
					mwexec("/sbin/ifconfig " . escapeshellarg($realif) . " inet6 {$wancfg['ipaddrv6']} prefixlen " . escapeshellarg($wancfg['subnetv6']));
4370
				}
4371
			}
4372
			break;
4373
	}
4374

    
4375
	if (!platform_booting()) {
4376
		link_interface_to_vips($interface, "update");
4377

    
4378
		if ($tunnelif != 'gre') {
4379
			$gre = link_interface_to_tunnelif($interface, 'gre');
4380
			array_walk($gre, 'interface_gre_configure');
4381
		}
4382

    
4383
		if ($tunnelif != 'gif') {
4384
			$gif = link_interface_to_tunnelif($interface, 'gif');
4385
			array_walk($gif, 'interface_gif_configure');
4386
		}
4387

    
4388
		if (($linkupevent == false) || (substr($realif, 0, 4) == "ovpn") || (substr($realif, 0, 5) == "ipsec")) {
4389
			unset($bridgetmp);
4390
			$bridgetmp = link_interface_to_bridge($interface);
4391
			if (!empty($bridgetmp)) {
4392
				interface_bridge_add_member($bridgetmp, $realif);
4393
			}
4394
		}
4395

    
4396
		$grouptmp = link_interface_to_group($interface);
4397
		if (!empty($grouptmp)) {
4398
			array_walk($grouptmp, 'interface_group_add_member');
4399
		}
4400

    
4401
		if ($interface == "lan") {
4402
			/* make new hosts file */
4403
			system_hosts_generate();
4404
		}
4405

    
4406
		if ($reloadall == true) {
4407

    
4408
			/* reconfigure static routes (kernel may have deleted them) */
4409
			system_routing_configure($interface);
4410

    
4411
			/* reload ipsec tunnels */
4412
			send_event("service reload ipsecdns");
4413

    
4414
			if (isset($config['dnsmasq']['enable'])) {
4415
				services_dnsmasq_configure();
4416
			}
4417

    
4418
			if (isset($config['unbound']['enable'])) {
4419
				services_unbound_configure();
4420
			}
4421

    
4422
			/* update dyndns */
4423
			send_event("service reload dyndns {$interface}");
4424

    
4425
			/* reload captive portal */
4426
			if (!function_exists('captiveportal_init_rules_byinterface')) {
4427
				require_once('captiveportal.inc');
4428
			}
4429
			captiveportal_init_rules_byinterface($interface);
4430
		}
4431
	}
4432

    
4433
	if (!empty($wancfg['descr'])) {
4434
		mwexec("/sbin/ifconfig " . escapeshellarg($wancfg['if']) . " description " . escapeshellarg($wancfg['descr']));
4435
	};
4436

    
4437
	interfaces_staticarp_configure($interface);
4438
	return 0;
4439
}
4440

    
4441
function interface_track6_configure($interface = "lan", $wancfg, $linkupevent = false) {
4442
	global $config, $g;
4443

    
4444
	if (!is_array($wancfg)) {
4445
		return;
4446
	}
4447

    
4448
	if (!isset($wancfg['enable'])) {
4449
		return;
4450
	}
4451

    
4452
	/* If the interface is not configured via another, exit */
4453
	if (empty($wancfg['track6-interface'])) {
4454
		return;
4455
	}
4456

    
4457
	/* always configure a link-local of fe80::1:1 on the track6 interfaces */
4458
	$realif = get_real_interface($interface);
4459
	$linklocal = find_interface_ipv6_ll($realif, true);
4460
	if (!empty($linklocal) && $linklocal != "fe80::1:1%{$realif}") {
4461
		mwexec("/sbin/ifconfig {$realif} inet6 fe80::1:1%{$realif} alias");
4462
	}
4463

    
4464
	$trackcfg = $config['interfaces'][$wancfg['track6-interface']];
4465
	if (!isset($trackcfg['enable'])) {
4466
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $wancfg['track6-interface']));
4467
		return;
4468
	}
4469

    
4470
	switch ($trackcfg['ipaddrv6']) {
4471
		case "6to4":
4472
			if ($g['debug']) {
4473
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4474
			}
4475
			interface_track6_6to4_configure($interface, $wancfg);
4476
			break;
4477
		case "6rd":
4478
			if ($g['debug']) {
4479
				log_error(sprintf(gettext('Interface %1$s configured via %2$s type %3$s'), $interface, $wancfg['track6-interface'], $type));
4480
			}
4481
			interface_track6_6rd_configure($interface, $wancfg);
4482
			break;
4483
		case "dhcp6":
4484
			if ($linkupevent == true) {
4485
				/*
4486
				 * NOTE: Usually come here from rc.linkup calling so just call directly instead of generating event
4487
				 * 	Instead of disrupting all other v4 configuration just restart DHCPv6 client for now
4488
				 *
4489
				 * XXX: Probably DHCPv6 client should handle this automagically itself?
4490
				 */
4491
				$pidv6 = find_dhcp6c_process();
4492
				if ($pidv6) {
4493
					posix_kill($pidv6, SIGHUP);
4494
				}
4495
			}
4496
			break;
4497
	}
4498

    
4499
	if ($linkupevent == false && !platform_booting()) {
4500
		if (!function_exists('services_dhcpd_configure')) {
4501
			require_once("services.inc");
4502
		}
4503

    
4504
		/* restart dns servers (defering dhcpd reload) */
4505
		if (isset($config['unbound']['enable'])) {
4506
			services_unbound_configure(false);
4507
		}
4508
		if (isset($config['dnsmasq']['enable'])) {
4509
			services_dnsmasq_configure(false);
4510
		}
4511

    
4512
		/* reconfigure dhcpdv6 (leaving dhcpdv4 alone) */
4513
		services_dhcpd_configure("inet6");
4514
	}
4515

    
4516
	return 0;
4517
}
4518

    
4519
function interface_track6_6rd_configure($interface = "lan", $lancfg) {
4520
	global $config, $g;
4521
	global $interface_ipv6_arr_cache;
4522
	global $interface_snv6_arr_cache;
4523

    
4524
	if (!is_array($lancfg)) {
4525
		return;
4526
	}
4527

    
4528
	/* If the interface is not configured via another, exit */
4529
	if (empty($lancfg['track6-interface'])) {
4530
		return;
4531
	}
4532

    
4533
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4534
	if (empty($wancfg)) {
4535
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4536
		return;
4537
	}
4538

    
4539
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4540
	if (!is_ipaddrv4($ip4address)) { /* XXX: This should not be needed by 6rd || (is_private_ip($ip4address))) { */
4541
		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']));
4542
		return;
4543
	}
4544
	$hexwanv4 = return_hex_ipv4($ip4address);
4545

    
4546
	/* create the long prefix notation for math, save the prefix length */
4547
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4548
	$rd6prefixlen = $rd6prefix[1];
4549
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4550

    
4551
	/* binary presentation of the prefix for all 128 bits. */
4552
	$rd6lanbin = convert_ipv6_to_128bit($rd6prefix);
4553

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

    
4559
	/* add the custom prefix id, max 32bits long? (64 bits - (prefixlen + (32 - v4plen)) */
4560
	/* 64 - (37 + (32 - 17)) = 8 == /52 */
4561
	$restbits = 64 - ($rd6prefixlen + (32 - $wancfg['prefix-6rd-v4plen']));
4562
	// echo "64 - (prefixlen {$rd6prefixlen} + v4len (32 - {$wancfg['prefix-6rd-v4plen']})) = {$restbits} \n";
4563
	$rd6lanbin .= substr(sprintf("%032b", str_pad($lancfg['track6-prefix-id'], 32, "0", STR_PAD_LEFT)), (32 - $restbits), 32);
4564
	/* fill the rest out with zeros */
4565
	$rd6lanbin = str_pad($rd6lanbin, 128, "0", STR_PAD_RIGHT);
4566

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

    
4570
	$lanif = get_real_interface($interface);
4571
	$oip = find_interface_ipv6($lanif);
4572
	if (is_ipaddrv6($oip)) {
4573
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4574
	}
4575
	unset($interface_ipv6_arr_cache[$lanif]);
4576
	unset($interface_snv6_arr_cache[$lanif]);
4577
	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));
4578
	mwexec("/sbin/ifconfig {$lanif} inet6 {$rd6lan} prefixlen 64");
4579

    
4580
	return 0;
4581
}
4582

    
4583
function interface_track6_6to4_configure($interface = "lan", $lancfg) {
4584
	global $config, $g;
4585
	global $interface_ipv6_arr_cache;
4586
	global $interface_snv6_arr_cache;
4587

    
4588
	if (!is_array($lancfg)) {
4589
		return;
4590
	}
4591

    
4592
	/* If the interface is not configured via another, exit */
4593
	if (empty($lancfg['track6-interface'])) {
4594
		return;
4595
	}
4596

    
4597
	$wancfg = $config['interfaces'][$lancfg['track6-interface']];
4598
	if (empty($wancfg)) {
4599
		log_error(sprintf(gettext('Interface %1$s tracking non-existent interface %2$s'), $interface, $lancfg['track6-interface']));
4600
		return;
4601
	}
4602

    
4603
	$ip4address = get_interface_ip($lancfg['track6-interface']);
4604
	if (!is_ipaddrv4($ip4address) || is_private_ip($ip4address)) {
4605
		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']));
4606
		return;
4607
	}
4608
	$hexwanv4 = return_hex_ipv4($ip4address);
4609

    
4610
	/* create the long prefix notation for math, save the prefix length */
4611
	$sixto4prefix = "2002::";
4612
	$sixto4prefixlen = 16;
4613
	$sixto4prefix = Net_IPv6::uncompress($sixto4prefix);
4614

    
4615
	/* binary presentation of the prefix for all 128 bits. */
4616
	$sixto4lanbin = convert_ipv6_to_128bit($sixto4prefix);
4617

    
4618
	/* just save the left prefix length bits */
4619
	$sixto4lanbin = substr($sixto4lanbin, 0, $sixto4prefixlen);
4620
	/* add the v4 address */
4621
	$sixto4lanbin .= sprintf("%032b", hexdec($hexwanv4));
4622
	/* add the custom prefix id */
4623
	$sixto4lanbin .= sprintf("%016b", $lancfg['track6-prefix-id']);
4624
	/* fill the rest out with zeros */
4625
	$sixto4lanbin = str_pad($sixto4lanbin, 128, "0", STR_PAD_RIGHT);
4626

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

    
4630
	$lanif = get_real_interface($interface);
4631
	$oip = find_interface_ipv6($lanif);
4632
	if (is_ipaddrv6($oip)) {
4633
		mwexec("/sbin/ifconfig {$lanif} inet6 {$oip} delete");
4634
	}
4635
	unset($interface_ipv6_arr_cache[$lanif]);
4636
	unset($interface_snv6_arr_cache[$lanif]);
4637
	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));
4638
	mwexec("/sbin/ifconfig {$lanif} inet6 {$sixto4lan} prefixlen 64");
4639

    
4640
	return 0;
4641
}
4642

    
4643
function interface_6rd_configure($interface = "wan", $wancfg) {
4644
	global $config, $g;
4645

    
4646
	/* because this is a tunnel interface we can only function
4647
	 *	with a public IPv4 address on the interface */
4648

    
4649
	if (!is_array($wancfg)) {
4650
		return;
4651
	}
4652

    
4653
	if (!is_module_loaded('if_stf.ko')) {
4654
		mwexec('/sbin/kldload if_stf.ko');
4655
	}
4656

    
4657
	$wanif = get_real_interface($interface);
4658
	$ip4address = find_interface_ip($wanif);
4659
	if (!is_ipaddrv4($ip4address)) {
4660
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4661
		return false;
4662
	}
4663
	$hexwanv4 = return_hex_ipv4($ip4address);
4664

    
4665
	if (!is_numeric($wancfg['prefix-6rd-v4plen'])) {
4666
		$wancfg['prefix-6rd-v4plen'] = 0;
4667
	}
4668

    
4669
	/* create the long prefix notation for math, save the prefix length */
4670
	$rd6prefix = explode("/", $wancfg['prefix-6rd']);
4671
	$rd6prefixlen = $rd6prefix[1];
4672
	$brgw = explode('.', $wancfg['gateway-6rd']);
4673
	$rd6brgw = substr(ip6_to_bin($rd6prefix[0]), 0, $rd6prefixlen);
4674
	$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);
4675
	if (strlen($rd6brgw) < 128) {
4676
		$rd6brgw = str_pad($rd6brgw, 128, '0', STR_PAD_RIGHT);
4677
	}
4678
	$rd6brgw = bin_to_compressed_ip6($rd6brgw);
4679
	unset($brgw);
4680
	$rd6prefix = Net_IPv6::uncompress($rd6prefix[0]);
4681

    
4682
	/* binary presentation of the prefix for all 128 bits. */
4683
	$rd6prefixbin = convert_ipv6_to_128bit($rd6prefix);
4684

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

    
4692
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4693
	$rd6prefix = convert_128bit_to_ipv6($rd6prefixbin);
4694

    
4695

    
4696
	/* XXX: need to extend to support variable prefix size for v4 */
4697
	$stfiface = "{$interface}_stf";
4698
	if (does_interface_exist($stfiface)) {
4699
		pfSense_interface_destroy($stfiface);
4700
	}
4701
	$tmpstfiface = pfSense_interface_create2("stf");
4702
	pfSense_interface_rename($tmpstfiface, $stfiface);
4703
	pfSense_interface_flags($stfiface, IFF_LINK2);
4704
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$rd6prefix}/{$rd6prefixlen}");
4705
	mwexec("/sbin/ifconfig {$stfiface} stfv4br " . escapeshellarg($wancfg['gateway-6rd']));
4706
	if ($wancfg['prefix-6rd-v4plen'] >= 0 && $wancfg['prefix-6rd-v4plen'] <= 32) {
4707
		mwexec("/sbin/ifconfig {$stfiface} stfv4net {$ip4address}/" . escapeshellarg($wancfg['prefix-6rd-v4plen']));
4708
	}
4709
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4710
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4711
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4712
	} elseif ($parentmtu > 1300) {
4713
		set_interface_mtu($stfiface, $parentmtu - 20);
4714
	}
4715
	if ($g['debug']) {
4716
		log_error("Created 6rd interface {$stfiface} {$rd6prefix}/{$rd6prefixlen}");
4717
	}
4718

    
4719
	/* write out a default router file */
4720
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$rd6brgw}\n");
4721
	unlink_if_exists("{$g['tmp_path']}/{$wanif}_routerv6.last");
4722
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$rd6brgw}\n");
4723

    
4724
	$ip4gateway = get_interface_gateway($interface);
4725
	if (is_ipaddrv4($ip4gateway)) {
4726
		route_add_or_change($wancfg['gateway-6rd'], $ip4gateway);
4727
	}
4728

    
4729
	/* configure dependent interfaces */
4730
	if (!platform_booting()) {
4731
		link_interface_to_track6($interface, "update");
4732
	}
4733

    
4734
	return 0;
4735
}
4736

    
4737
function interface_6to4_configure($interface = "wan", $wancfg) {
4738
	global $config, $g;
4739

    
4740
	/* because this is a tunnel interface we can only function
4741
	 *	with a public IPv4 address on the interface */
4742

    
4743
	if (!is_array($wancfg)) {
4744
		return;
4745
	}
4746

    
4747
	$wanif = get_real_interface($interface);
4748
	$ip4address = find_interface_ip($wanif);
4749
	if ((!is_ipaddrv4($ip4address)) || (is_private_ip($ip4address))) {
4750
		log_error(sprintf(gettext('The interface IPv4 \'%1$s\' address on interface \'%2$s\' is not public, not configuring 6RD tunnel'), $ip4address, $wanif));
4751
		return false;
4752
	}
4753

    
4754
	/* create the long prefix notation for math, save the prefix length */
4755
	$stfprefixlen = 16;
4756
	$stfprefix = Net_IPv6::uncompress("2002::");
4757
	$stfarr = explode(":", $stfprefix);
4758
	$v4prefixlen = "0";
4759

    
4760
	/* we need the hex form of the interface IPv4 address */
4761
	$ip4arr = explode(".", $ip4address);
4762
	$hexwanv4 = "";
4763
	foreach ($ip4arr as $octet) {
4764
		$hexwanv4 .= sprintf("%02x", $octet);
4765
	}
4766

    
4767
	/* we need the hex form of the broker IPv4 address */
4768
	$ip4arr = explode(".", "192.88.99.1");
4769
	$hexbrv4 = "";
4770
	foreach ($ip4arr as $octet) {
4771
		$hexbrv4 .= sprintf("%02x", $octet);
4772
	}
4773

    
4774
	/* binary presentation of the prefix for all 128 bits. */
4775
	$stfprefixbin = "";
4776
	foreach ($stfarr as $element) {
4777
		$stfprefixbin .= sprintf("%016b", hexdec($element));
4778
	}
4779
	/* just save the left prefix length bits */
4780
	$stfprefixstartbin = substr($stfprefixbin, 0, $stfprefixlen);
4781

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

    
4786
	/* for the local subnet too. */
4787
	$stflanbin = substr(sprintf("%032b", hexdec($hexwanv4)), $v4prefixlen, 32);
4788
	$stflanbin = str_pad($stfprefixstartbin . $stflanbin, 128, "0", STR_PAD_RIGHT);
4789

    
4790
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4791
	$stfbrarr = array();
4792
	$stfbrbinarr = array();
4793
	$stfbrbinarr = str_split($stfbrokerbin, 16);
4794
	foreach ($stfbrbinarr as $bin) {
4795
		$stfbrarr[] = dechex(bindec($bin));
4796
	}
4797
	$stfbrgw = text_to_compressed_ip6(implode(":", $stfbrarr));
4798

    
4799
	/* convert the 128 bits for the broker address back into a valid IPv6 address */
4800
	$stflanarr = array();
4801
	$stflanbinarr = array();
4802
	$stflanbinarr = str_split($stflanbin, 16);
4803
	foreach ($stflanbinarr as $bin) {
4804
		$stflanarr[] = dechex(bindec($bin));
4805
	}
4806
	$stflanpr = text_to_compressed_ip6(implode(":", $stflanarr));
4807
	$stflanarr[7] = 1;
4808
	$stflan = text_to_compressed_ip6(implode(":", $stflanarr));
4809

    
4810
	/* setup the stf interface */
4811
	if (!is_module_loaded("if_stf")) {
4812
		mwexec("/sbin/kldload if_stf.ko");
4813
	}
4814
	$stfiface = "{$interface}_stf";
4815
	if (does_interface_exist($stfiface)) {
4816
		pfSense_interface_destroy($stfiface);
4817
	}
4818
	$tmpstfiface = pfSense_interface_create2("stf");
4819
	pfSense_interface_rename($tmpstfiface, $stfiface);
4820
	pfSense_interface_flags($stfiface, IFF_LINK2);
4821
	mwexec("/sbin/ifconfig {$stfiface} inet6 {$stflanpr} prefixlen 16");
4822

    
4823
	$parentmtu = get_interface_mtu(get_real_interface($interface));
4824
	if (isset($wancfg['mtu']) && ($wancfg['mtu'] >= 1300)) {
4825
		set_interface_mtu($stfiface, $wancfg['mtu'] - 20);
4826
	} elseif ($parentmtu > 1300) {
4827
		set_interface_mtu($stfiface, $parentmtu - 20);
4828
	}
4829
	if ($g['debug']) {
4830
		log_error("Set IPv6 address inet6 {$stflanpr} prefixlen 16 for {$stfiface}, route {$stfbrgw}");
4831
	}
4832

    
4833
	/* write out a default router file */
4834
	file_put_contents("{$g['tmp_path']}/{$wanif}_routerv6", "{$stfbrgw}");
4835
	unlink_if_exists("{$g['tmp_path']}/{$wanif}_routerv6.last");
4836
	file_put_contents("{$g['tmp_path']}/{$wanif}_defaultgwv6", "{$stfbrgw}");
4837

    
4838
	$ip4gateway = get_interface_gateway($interface);
4839
	if (is_ipaddrv4($ip4gateway)) {
4840
		route_add_or_change("192.88.99.1", $ip4gateway);
4841
	}
4842

    
4843
	if (!platform_booting()) {
4844
		link_interface_to_track6($interface, "update");
4845
	}
4846

    
4847
	return 0;
4848
}
4849

    
4850
function interface_dhcpv6_configure($ifconf = "wan", $ifcfg, $destroy = false) {
4851
	global $config, $g;
4852

    
4853
	$dhcp6cconf = "";
4854
	$id = "0";
4855
	$dhcp6cinterfaces = array();
4856
	$dhcp6cifs_descr = array();
4857
	$dhcp6crealifs = array();
4858
	$debugOption = "-d";
4859
	$noreleaseOption = "";
4860

    
4861
	if (!empty($config['system']['global-v6duid'])) {
4862
		// Write the DUID file
4863
		if(!write_dhcp6_duid($config['system']['global-v6duid'])) {
4864
		    log_error(gettext("Failed to write user DUID file!"));
4865
		}
4866
	}
4867

    
4868
	foreach ($config['interfaces'] as $interface => $wancfg) {
4869
		$wanif = get_real_interface($interface, "inet6");
4870

    
4871
		if (($ifconf == $interface) && $destroy) {
4872
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_script.sh");
4873
			unlink_if_exists("{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh");
4874
			unlink_if_exists("{$g['varetc_path']}/rtsold_{$wanif}_script.sh");
4875
			continue;
4876
		}
4877

    
4878
		if (!isset($wancfg['enable']) || (($ifconf == $interface) && $destroy) ||
4879
		    (($wancfg['ipaddrv6'] != 'dhcp6') && ($wancfg['ipaddrv6'] != 'slaac'))) {
4880
			continue;
4881
		}
4882

    
4883
		$dhcp6cinterfaces[$interface] = $wancfg;
4884

    
4885
		if (isset($config['system']['dhcp6debug'])) {
4886
			$debugOption = "-D";
4887
		}
4888
		if (isset($config['system']['dhcp6norelease'])) {
4889
			$noreleaseOption = "-n";
4890
		}
4891

    
4892
		/* accept router advertisements for this interface                 */
4893
		/* Moved to early in the function as sometimes interface not ready */
4894
		/* RTSOLD fails as interface does not accept .....                 */
4895

    
4896
		log_error("Accept router advertisements on interface {$wanif} ");
4897
		mwexec("/sbin/ifconfig {$wanif} inet6 accept_rtadv");
4898

    
4899
		if ($wancfg['adv_dhcp6_config_file_override']) {
4900
			// DHCP6 Config File Override
4901
			$dhcp6cconf = DHCP6_Config_File_Override($wancfg, $wanif);
4902
		} elseif ($wancfg['adv_dhcp6_config_advanced']) {
4903
			// DHCP6 Config File Advanced
4904
			$dhcp6cconf = DHCP6_Config_File_Advanced($interface, $wancfg, $wanif);
4905
		} else {
4906
			// DHCP6 Config File Basic
4907
			$dhcp6cconf .= "interface {$wanif} {\n";
4908

    
4909
			/* for SLAAC interfaces we do fire off a dhcp6 client for just our name servers */
4910
			if ($wancfg['ipaddrv6'] == "slaac") {
4911
				$dhcp6cconf .= "\tinformation-only;\n";
4912
				$dhcp6cconf .= "\trequest domain-name-servers;\n";
4913
				$dhcp6cconf .= "\trequest domain-name;\n";
4914
				$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4915
				$dhcp6cconf .= "};\n";
4916
			} else {
4917
				$trackiflist = array();
4918
				$iflist = link_interface_to_track6($interface);
4919
				foreach ($iflist as $ifname => $ifcfg) {
4920
					if (is_numeric($ifcfg['track6-prefix-id'])) {
4921
						$trackiflist[$ifname] = $ifcfg;
4922
					}
4923
				}
4924

    
4925
				/* skip address request if this is set */
4926
				if (!isset($wancfg['dhcp6prefixonly'])) {
4927
					$dhcp6cconf .= "\tsend ia-na {$id};\t# request stateful address\n";
4928
				}
4929
				if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4930
					$dhcp6cconf .= "\tsend ia-pd {$id};\t# request prefix delegation\n";
4931
				}
4932

    
4933
				$dhcp6cconf .= "\trequest domain-name-servers;\n";
4934
				$dhcp6cconf .= "\trequest domain-name;\n";
4935

    
4936
				/*
4937
				 * dhcp6c will run different scripts depending on
4938
				 * whether dhcpwithoutra is set or unset.
4939
				 */
4940
				if (isset($wancfg['dhcp6withoutra'])) {
4941
					$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\"; # we'd like nameservers and RTSOLD to do all the work\n";
4942
				} else {
4943
					$dhcp6cconf .= "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\"; # we'd like some nameservers please\n";
4944
				}
4945
				$dhcp6cconf .= "};\n";
4946

    
4947
				if (!isset($wancfg['dhcp6prefixonly'])) {
4948
					$dhcp6cconf .= "id-assoc na {$id} { };\n";
4949
				}
4950

    
4951
				if (is_numeric($wancfg['dhcp6-ia-pd-len'])) {
4952
					/* Setup the prefix delegation */
4953
					$dhcp6cconf .= "id-assoc pd {$id} {\n";
4954
					$preflen = 64 - $wancfg['dhcp6-ia-pd-len'];
4955
					if (isset($wancfg['dhcp6-ia-pd-send-hint'])) {
4956
						$dhcp6cconf .= "\tprefix ::/{$preflen} infinity;\n";
4957
					}
4958
					foreach ($trackiflist as $friendly => $ifcfg) {
4959
						if ($g['debug']) {
4960
							log_error("setting up $ifdescr - {$ifcfg['track6-prefix-id']}");
4961
						}
4962
						$realif = get_real_interface($friendly);
4963
						$dhcp6cconf .= "\tprefix-interface {$realif} {\n";
4964
						$dhcp6cconf .= "\t\tsla-id {$ifcfg['track6-prefix-id']};\n";
4965
						$dhcp6cconf .= "\t\tsla-len {$wancfg['dhcp6-ia-pd-len']};\n";
4966
						$dhcp6cconf .= "\t};\n";
4967
					}
4968
					unset($preflen, $iflist, $ifcfg, $ifname);
4969
					$dhcp6cconf .= "};\n\n";
4970
				}
4971
				unset($trackiflist);
4972
			}
4973
			$id++;
4974
		}
4975

    
4976
		/*************** Script Debug Logging ***************************
4977
		Both dhcp6 scripts now have a logging message built in.
4978
		These logging messages ONLY appear if dhcp6c debug logging is set.
4979
		The logging messages appear in the dhcp section of the logs,
4980
		not in system.
4981

    
4982
		These scripts now also take advantage of the REASON= env vars
4983
		supplied by dhcp6c.
4984
		****************************************************************/
4985

    
4986
		/* Script create for dhcp6withoutRA mode */
4987
		/* dhcp6c will launch rtsold. rtsold will then run the wan ipv6 configure */
4988
		$dhcp6cscriptwithoutra = "#!/bin/sh\n";
4989
		$dhcp6cscriptwithoutra .= "# This shell script launches rtsold.\n";
4990
		$dhcp6cscriptwithoutra .= "dmips=\${new_domain_name_servers}\n";
4991
		$dhcp6cscriptwithoutra .= "dmnames=\${new_domain_name}\n";
4992
		$dhcp6cscriptwithoutra .= "dreason=\${REASON}\n";
4993
		// Need to pass params to  the final script
4994
		$dhcp6cscriptwithoutra .= "echo \$dmips > /tmp/{$wanif}_domain_name_servers\n";
4995
		$dhcp6cscriptwithoutra .= "echo \$dmnames > /tmp/{$wanif}_new_domain_name\n";
4996
		$dhcp6cscriptwithoutra .= "echo \$dreason > /tmp/{$wanif}_reason\n";
4997
		$dhcp6cscriptwithoutra .= "case \$REASON in\n";
4998
		$dhcp6cscriptwithoutra .= "REQUEST)\n";
4999
		$dhcp6cscriptwithoutra .= "/bin/sleep 2\n";
5000
		$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";
5001
		if ($debugOption == '-D') {
5002
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c REQUEST on {$wanif} - running rtsold\"\n";
5003
		}
5004
		$dhcp6cscriptwithoutra .= ";;\n";
5005
		$dhcp6cscriptwithoutra .= "REBIND)\n";
5006
		if ($debugOption == '-D') {
5007
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
5008
		}
5009
		$dhcp6cscriptwithoutra .= ";;\n";
5010
		if (isset($wancfg['dhcp6norelease'])) {
5011
			$dhcp6cscriptwithoutra .= "EXIT)\n";
5012
		} else {
5013
			$dhcp6cscriptwithoutra .= "RELEASE)\n";
5014
		}
5015
		if ($debugOption == '-D') {
5016
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c EXIT or RELEASE on {$wanif} running rc.newwanipv6\"\n";
5017
		}
5018
		$dhcp6cscriptwithoutra .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5019
		$dhcp6cscriptwithoutra .= ";;\n";
5020
		$dhcp6cscriptwithoutra .= "RENEW|INFO)\n";
5021
		if ($debugOption == '-D') {
5022
			$dhcp6cscriptwithoutra .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5023
		}
5024
		$dhcp6cscriptwithoutra .= "esac\n";
5025
		if (!@file_put_contents(
5026
		    "{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh",
5027
		    $dhcp6cscriptwithoutra)) {
5028
			printf("Error: cannot open " .
5029
			    "dhcp6c_{$interface}_dhcp6cwithoutra_script.sh in " .
5030
			    "interface_dhcpv6_configure() for writing.\n");
5031
			unset($dhcp6cscriptwithoutra);
5032
			return 1;
5033
		}
5034

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

    
5037
		/*
5038
		 * Dual mode wan_dhcp6c script with variations depending on node
5039
		 * dhcp6 will run the wan ipv6 configure
5040
		 */
5041
		$dhcp6cscript  = "#!/bin/sh\n";
5042
		$dhcp6cscript .= "# This shell script launches /etc/rc.newwanipv6 with a interface argument.\n";
5043
		if (!isset($wancfg['dhcp6withoutra'])) {
5044
			$dhcp6cscript .= "dmips=\${new_domain_name_servers}\n";
5045
			$dhcp6cscript .= "dmnames=\${new_domain_name}\n";
5046
			$dhcp6cscript .= "case \$REASON in\n";
5047
			$dhcp6cscript .= "REBIND)\n";
5048
			if ($debugOption == '-D') {
5049
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c rebind on {$wanif}\"\n";
5050
			}
5051
			$dhcp6cscript .= ";;\n";
5052
			$dhcp6cscript .= "REQUEST|";
5053
			if (isset($wancfg['dhcp6norelease'])) {
5054
				$dhcp6cscript .= "EXIT)\n";
5055
			} else {
5056
				$dhcp6cscript .= "RELEASE)\n";
5057
			}
5058
			if ($debugOption == '-D') {
5059
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c RELEASE, REQUEST or EXIT on {$wanif} running rc.newwanipv6\"\n";
5060
			}
5061
			$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5062
			$dhcp6cscript .= ";;\n";
5063
			$dhcp6cscript .= "RENEW|INFO)\n";
5064
			if ($debugOption == '-D') {
5065
				$dhcp6cscript .= "/usr/bin/logger -t dhcp6c \"dhcp6c renew, no change - bypassing update on {$wanif}\"\n";
5066
			}
5067
			$dhcp6cscript .= "esac\n";
5068
			$rtsold_ra_ifs[] = $wanif;
5069
		} else {
5070
			// Need to get the parameters from the dhcp6cwithoutRA run
5071
			$dhcp6cscript .= "dmips=\$(cat \"/tmp/{$wanif}_domain_name_servers\")\n";
5072
			$dhcp6cscript .= "dmnames=\$(cat \"/tmp/{$wanif}_new_domain_name\")\n";
5073
			$dhcp6cscript .= "/bin/sleep 1\n";
5074
			$dhcp6cscript .= "/usr/local/sbin/fcgicli -f /etc/rc.newwanipv6 -d \"interface={$wanif}&dmnames=\${dmnames}&dmips=\${dmips}\"\n";
5075
		}
5076

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

    
5087
	if (!empty($dhcp6cinterfaces)) {
5088
		/* wide-dhcp6c works for now. */
5089
		if (!@file_put_contents("{$g['varetc_path']}/dhcp6c.conf", $dhcp6cconf)) {
5090
			printf("Error: cannot open dhcp6c.conf in interface_dhcpv6_configure() for writing.\n");
5091
			return 1;
5092
		}
5093
		foreach ($dhcp6cinterfaces as $interface => $wancfg) {
5094
			$dhcp6cifs_descr[] = $interface . '(' . $wancfg['if'] . ')';
5095
			$dhcp6crealifs[] = $wancfg['if'];
5096
		}
5097
		$dhcp6cdescr = implode(',', $dhcp6cifs_descr);
5098
		$dhcp6cifs = implode(' ', $dhcp6crealifs);
5099
		foreach ($dhcp6cinterfaces as $interface => $wancfg) {
5100
			$wanif = get_real_interface($interface, "inet6");
5101

    
5102
			$rtsoldscript_header = <<<EOD
5103
#!/bin/sh
5104
# This shell script launches dhcp6c and configured gateways for this interface.
5105
if [ -n "\$2" ]; then
5106
	if [ -n "$(echo \$2 | /usr/bin/grep '^fe80')" ]; then
5107
		echo \$2\%{$wanif} > {$g['tmp_path']}/{$wanif}_routerv6
5108
		/bin/rm -f {$g['tmp_path']}/{$wanif}_routerv6.last
5109
		echo \$2\%{$wanif} > {$g['tmp_path']}/{$wanif}_defaultgwv6
5110
	else
5111
		echo \$2 > {$g['tmp_path']}/{$wanif}_routerv6
5112
		/bin/rm -f {$g['tmp_path']}/{$wanif}_routerv6.last
5113
		echo \$2 > {$g['tmp_path']}/{$wanif}_defaultgwv6
5114
	fi
5115
	/usr/bin/logger -t rtsold "Received RA specifying route \$2 for interface {$interface}({$wanif})"
5116
fi
5117

    
5118
EOD;
5119

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

    
5161
			/* Add wide-dhcp6c shell script here. Because we can not pass a argument to it. */
5162
			if (!@file_put_contents("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", $rtsoldscript)) {
5163
				printf("Error: cannot open rtsold_{$wanif}_script.sh in interface_dhcpv6_configure() for writing.\n");
5164
				return 1;
5165
			}
5166
			unset($rtsoldscript);
5167
			@chmod("{$g['varetc_path']}/rtsold_{$wanif}_script.sh", 0755);
5168
		}
5169

    
5170
		$realif = get_real_interface($ifconf, "inet6");
5171
		if (isvalidpid("{$g['varrun_path']}/rtsold_{$realif}.pid")) {
5172
			killbypid("{$g['varrun_path']}/rtsold_{$realif}.pid");
5173
			log_error("Killing running rtsold process");
5174
			sleep(2);
5175
		}
5176

    
5177
		if (file_exists("{$g['tmp_path']}/dhcp6c_ifs")) {
5178
			$dhcp6crealifs_run = unserialize(file_get_contents("{$g['tmp_path']}/dhcp6c_ifs"));
5179
		} else {
5180
			$dhcp6crealifs_run = array();
5181
		}
5182

    
5183
		if (($dhcp6crealifs != $dhcp6crealifs_run) || $destroy) {
5184
			kill_dhcp6client_process(false);
5185
			run_dhcp6client_process($dhcp6crealifs, $debugOption, $noreleaseOption);
5186
			file_put_contents("{$g['tmp_path']}/dhcp6c_ifs", serialize($dhcp6crealifs));
5187
			$dhcp6c_restarted = true;
5188
			if ($destroy) {
5189
				$track6 = link_interface_to_track6($ifconf);
5190
				if (is_array($track6) && !empty($track6)) {
5191
					/* remove stale track interfaces IP */
5192
					foreach ($track6 as $tr6ifname => $tr6cfg) {
5193
						interface_reconfigure($tr6if, true);
5194
					}
5195
				}
5196
			}
5197
		}
5198

    
5199
		if (isset($ifcfg['dhcp6withoutra']) && !$dhcp6c_restarted) {
5200
			/*
5201
			 * Start dhcp6c here if we don't want to wait for ra - calls
5202
			 * separate function
5203
			 *
5204
			 * In this mode dhcp6c launches rtsold via its script. RTSOLD
5205
			 * will then run the configure on receipt of the RA.
5206
			 *
5207
			 * Already started. interface_dhcpv6_configure() appears to get
5208
			 * called multiple times.
5209
			 *
5210
			 * Taking the interface down or releasing will kill the client.
5211
			 */
5212

    
5213
			/*
5214
			 * If the interface is being brought up, wait for the
5215
			 * interface to configure accept RA before launching.
5216
			 * Otherwise it is not ready to accept and will fail.
5217
			 */
5218
			sleep(3);
5219
			if (file_exists("/tmp/dhcp6c_lock")) {
5220
				reset_dhcp6client_process();
5221
			}
5222
		} elseif (!$destroy) {
5223
			/*
5224
			 * Fire up rtsold for IPv6 RAs, this backgrounds immediately
5225
			 * ( it does not background, it exits! ) It will launch dhcp6c
5226
			 * if dhcpwihtoutra is not set
5227
			 */
5228
			log_error("Starting rtsold process on {$ifconf}({$realif})");
5229
			sleep(2);
5230
			mwexec("/usr/sbin/rtsold -1 " .
5231
			    "-p {$g['varrun_path']}/rtsold_{$realif}.pid " .
5232
			    "-M {$g['varetc_path']}/rtsold_{$realif}_script.sh " .
5233
			    "-O {$g['varetc_path']}/rtsold_{$realif}_script.sh " .
5234
			    $realif);
5235
		}
5236
	} else {
5237
		kill_dhcp6client_process(true);
5238
		unlink_if_exists("{$g['varetc_path']}/dhcp6c.conf");
5239
		unlink_if_exists("{$g['tmp_path']}/dhcp6c_ifs");
5240
	}
5241

    
5242
	/*
5243
	 * NOTE: will be called from rtsold invoked script
5244
	 * link_interface_to_track6($interface, "update");
5245
	 */
5246

    
5247
	return 0;
5248
}
5249

    
5250
function DHCP6_Config_File_Advanced($interface, $wancfg, $wanif) {
5251
	global $g;
5252

    
5253
	$send_options = "";
5254
	if ($wancfg['adv_dhcp6_interface_statement_send_options'] != '') {
5255
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_send_options']);
5256
		foreach ($options as $option) {
5257
			$send_options .= "\tsend " . trim($option) . ";\n";
5258
		}
5259
	}
5260

    
5261
	$request_options = "";
5262
	if ($wancfg['adv_dhcp6_interface_statement_request_options'] != '') {
5263
		$options = DHCP_Config_Option_Split($wancfg['adv_dhcp6_interface_statement_request_options']);
5264
		foreach ($options as $option) {
5265
			$request_options .= "\trequest " . trim($option) . ";\n";
5266
		}
5267
	}
5268

    
5269
	$information_only = "";
5270
	if ($wancfg['adv_dhcp6_interface_statement_information_only_enable'] != '') {
5271
		$information_only = "\tinformation-only;\n";
5272
	}
5273

    
5274
	if (isset($wancfg['dhcp6withoutra'])) {
5275
		$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_dhcp6withoutra_script.sh\";\n";
5276
	} else {
5277
		$script = "\tscript \"{$g['varetc_path']}/dhcp6c_{$interface}_script.sh\";\n";
5278
	}
5279
	if ($wancfg['adv_dhcp6_interface_statement_script'] != '') {
5280
		$script = "\tscript \"{$wancfg['adv_dhcp6_interface_statement_script']}\";\n";
5281
	}
5282

    
5283
	$interface_statement  = "interface";
5284
	$interface_statement .= " {$wanif}";
5285
	$interface_statement .= " {\n";
5286
	$interface_statement .= "$send_options";
5287
	$interface_statement .= "$request_options";
5288
	$interface_statement .= "$information_only";
5289
	$interface_statement .= "$script";
5290
	$interface_statement .= "};\n";
5291

    
5292
	$id_assoc_statement_address = "";
5293
	if ($wancfg['adv_dhcp6_id_assoc_statement_address_enable'] != '') {
5294
		$id_assoc_statement_address .= "id-assoc";
5295
		$id_assoc_statement_address .= " na";
5296
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_id'])) {
5297
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_id']}";
5298
		}
5299
		$id_assoc_statement_address .= " { ";
5300

    
5301
		if (($wancfg['adv_dhcp6_id_assoc_statement_address'] != '') &&
5302
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_pltime']) ||
5303
		    ($wancfg['adv_dhcp6_id_assoc_statement_address_pltime'] == 'infinity'))) {
5304
			$id_assoc_statement_address .= "\n\taddress";
5305
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address']}";
5306
			$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_pltime']}";
5307
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'])) ||
5308
			    ($wancfg['adv_dhcp6_id_assoc_statement_address_vltime'] == 'infinity')) {
5309
				$id_assoc_statement_address .= " {$wancfg['adv_dhcp6_id_assoc_statement_address_vltime']}";
5310
			}
5311
			$id_assoc_statement_address .= ";\n";
5312
		}
5313

    
5314
		$id_assoc_statement_address .= "};\n";
5315
	}
5316

    
5317
	$id_assoc_statement_prefix = "";
5318
	if ($wancfg['adv_dhcp6_id_assoc_statement_prefix_enable'] != '') {
5319
		$id_assoc_statement_prefix .= "id-assoc";
5320
		$id_assoc_statement_prefix .= " pd";
5321
		if (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_id'])) {
5322
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_id']}";
5323
		}
5324
		$id_assoc_statement_prefix .= " { ";
5325

    
5326
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') &&
5327
		    (is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']) ||
5328
		    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime'] == 'infinity'))) {
5329
			$id_assoc_statement_prefix .= "\n\tprefix";
5330
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix']}";
5331
			$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_pltime']}";
5332
			if ((is_numeric($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'])) ||
5333
			    ($wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime'] == 'infinity')) {
5334
				$id_assoc_statement_prefix .= " {$wancfg['adv_dhcp6_id_assoc_statement_prefix_vltime']}";
5335
			}
5336
			$id_assoc_statement_prefix .= ";";
5337
		}
5338

    
5339
		$realif = get_real_interface($wancfg['adv_dhcp6_prefix_selected_interface']);
5340
		if (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id'])) {
5341
			$id_assoc_statement_prefix .= "\n\tprefix-interface";
5342
			$id_assoc_statement_prefix .= " {$realif}";
5343
			$id_assoc_statement_prefix .= " {\n";
5344
			$id_assoc_statement_prefix .= "\t\tsla-id {$wancfg['adv_dhcp6_prefix_interface_statement_sla_id']};\n";
5345
			if (($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] >= 0) &&
5346
			    ($wancfg['adv_dhcp6_prefix_interface_statement_sla_len'] <= 128)) {
5347
				$id_assoc_statement_prefix .= "\t\tsla-len {$wancfg['adv_dhcp6_prefix_interface_statement_sla_len']};\n";
5348
			}
5349
			$id_assoc_statement_prefix .= "\t};";
5350
		}
5351

    
5352
		if (($wancfg['adv_dhcp6_id_assoc_statement_prefix'] != '') ||
5353
		    (is_numeric($wancfg['adv_dhcp6_prefix_interface_statement_sla_id']))) {
5354
			$id_assoc_statement_prefix .= "\n";
5355
		}
5356

    
5357
		$id_assoc_statement_prefix .= "};\n";
5358
	}
5359

    
5360
	$authentication_statement = "";
5361
	if (($wancfg['adv_dhcp6_authentication_statement_authname'] != '') &&
5362
	    ($wancfg['adv_dhcp6_authentication_statement_protocol'] == 'delayed')) {
5363
		$authentication_statement .= "authentication";
5364
		$authentication_statement .= " {$wancfg['adv_dhcp6_authentication_statement_authname']}";
5365
		$authentication_statement .= " {\n";
5366
		$authentication_statement .= "\tprotocol {$wancfg['adv_dhcp6_authentication_statement_protocol']};\n";
5367
		if (preg_match("/(hmac(-)?md5)||(HMAC(-)?MD5)/", $wancfg['adv_dhcp6_authentication_statement_algorithm'])) {
5368
			$authentication_statement .= "\talgorithm {$wancfg['adv_dhcp6_authentication_statement_algorithm']};\n";
5369
		}
5370
		if ($wancfg['adv_dhcp6_authentication_statement_rdm'] == 'monocounter') {
5371
			$authentication_statement .= "\trdm {$wancfg['adv_dhcp6_authentication_statement_rdm']};\n";
5372
		}
5373
		$authentication_statement .= "};\n";
5374
	}
5375

    
5376
	$key_info_statement = "";
5377
	if (($wancfg['adv_dhcp6_key_info_statement_keyname'] != '') &&
5378
	    ($wancfg['adv_dhcp6_key_info_statement_realm'] != '') &&
5379
	    (is_numeric($wancfg['adv_dhcp6_key_info_statement_keyid'])) &&
5380
	    ($wancfg['adv_dhcp6_key_info_statement_secret'] != '')) {
5381
		$key_info_statement .= "keyinfo";
5382
		$key_info_statement .= " {$wancfg['adv_dhcp6_key_info_statement_keyname']}";
5383
		$key_info_statement .= " {\n";
5384
		$key_info_statement .= "\trealm \"{$wancfg['adv_dhcp6_key_info_statement_realm']}\";\n";
5385
		$key_info_statement .= "\tkeyid {$wancfg['adv_dhcp6_key_info_statement_keyid']};\n";
5386
		$key_info_statement .= "\tsecret \"{$wancfg['adv_dhcp6_key_info_statement_secret']}\";\n";
5387
		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'])) {
5388
			$key_info_statement .= "\texpire \"{$wancfg['adv_dhcp6_key_info_statement_expire']}\";\n";
5389
		}
5390
		$key_info_statement .= "};\n";
5391
	}
5392

    
5393
	$dhcp6cconf  = $interface_statement;
5394
	$dhcp6cconf .= $id_assoc_statement_address;
5395
	$dhcp6cconf .= $id_assoc_statement_prefix;
5396
	$dhcp6cconf .= $authentication_statement;
5397
	$dhcp6cconf .= $key_info_statement;
5398

    
5399
	$dhcp6cconf = DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5400

    
5401
	return $dhcp6cconf;
5402
}
5403

    
5404

    
5405
function DHCP6_Config_File_Override($wancfg, $wanif) {
5406

    
5407
	$dhcp6cconf = @file_get_contents($wancfg['adv_dhcp6_config_file_override_path']);
5408

    
5409
	if ($dhcp6cconf === false) {
5410
		log_error(sprintf(gettext('Error: cannot open %s in DHCP6_Config_File_Override() for reading.'), $wancfg['adv_dhcp6_config_file_override_path']));
5411
		return '';
5412
	} else {
5413
		return DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);;
5414
	}
5415
}
5416

    
5417

    
5418
function DHCP6_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf) {
5419

    
5420
	$dhcp6cconf = DHCP_Config_File_Substitutions($wancfg, $wanif, $dhcp6cconf);
5421

    
5422
	return $dhcp6cconf;
5423
}
5424

    
5425

    
5426
function interface_dhcp_configure($interface = "wan") {
5427
	global $config, $g, $vlanprio_values;
5428

    
5429
	$ifcfg = $config['interfaces'][$interface];
5430
	if (empty($ifcfg)) {
5431
		$ifcfg = array();
5432
	}
5433

    
5434
	$dhclientconf_vlantag = "";
5435
	if (isset($ifcfg['dhcpvlanenable']) && isset($ifcfg['dhcpcvpt'])) {
5436
		$dhclientconf_vlantag = "vlan-pcp {$vlanprio_values[$ifcfg['dhcpcvpt']]};\n";
5437
	}
5438

    
5439
	/* generate dhclient_wan.conf */
5440
	$fd = fopen("{$g['varetc_path']}/dhclient_{$interface}.conf", "w");
5441
	if (!$fd) {
5442
		log_error(sprintf(gettext("Error: cannot open dhclient_%s.conf in interface_dhcp_configure() for writing."), $interface));
5443
		return 1;
5444
	}
5445

    
5446
	if ($ifcfg['dhcphostname']) {
5447
		$dhclientconf_hostname = "send dhcp-client-identifier \"{$ifcfg['dhcphostname']}\";\n";
5448
		$dhclientconf_hostname .= "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5449
	} else {
5450
		$dhclientconf_hostname = "";
5451
	}
5452

    
5453
	$realif = get_real_interface($interface);
5454
	if (empty($realif)) {
5455
		log_error(sprintf(gettext("Invalid interface \"%s\" in interface_dhcp_configure()"), $interface));
5456
		return 0;
5457
	}
5458
	$dhclientconf = "";
5459

    
5460
	$dhclientconf .= <<<EOD
5461
interface "{$realif}" {
5462
	supersede interface-mtu 0;
5463
	timeout 60;
5464
	retry 15;
5465
	select-timeout 0;
5466
	initial-interval 1;
5467
	{$dhclientconf_vlantag}
5468
	{$dhclientconf_hostname}
5469
	script "/usr/local/sbin/pfSense-dhclient-script";
5470
EOD;
5471

    
5472
	if (validate_ipv4_list($ifcfg['dhcprejectfrom'])) {
5473
		$dhclientconf .= <<<EOD
5474

    
5475
	reject {$ifcfg['dhcprejectfrom']};
5476
EOD;
5477
	}
5478
	$dhclientconf .= <<<EOD
5479

    
5480
}
5481

    
5482
EOD;
5483

    
5484
	// DHCP Config File Advanced
5485
	if ($ifcfg['adv_dhcp_config_advanced']) {
5486
		$dhclientconf = DHCP_Config_File_Advanced($interface, $ifcfg, $realif);
5487
	}
5488

    
5489
	if (is_ipaddr($ifcfg['alias-address'])) {
5490
		$subnetmask = gen_subnet_mask($ifcfg['alias-subnet']);
5491
		$dhclientconf .= <<<EOD
5492
alias {
5493
	interface "{$realif}";
5494
	fixed-address {$ifcfg['alias-address']};
5495
	option subnet-mask {$subnetmask};
5496
}
5497

    
5498
EOD;
5499
	}
5500

    
5501
	// DHCP Config File Override
5502
	if ($ifcfg['adv_dhcp_config_file_override']) {
5503
		$dhclientconf = DHCP_Config_File_Override($ifcfg, $realif);
5504
	}
5505

    
5506
	fwrite($fd, $dhclientconf);
5507
	fclose($fd);
5508

    
5509
	/* bring wan interface up before starting dhclient */
5510
	if ($realif) {
5511
		interfaces_bring_up($realif);
5512
	}
5513

    
5514
	/* Make sure dhclient is not running */
5515
	kill_dhclient_process($realif);
5516

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

    
5520
	return 0;
5521
}
5522

    
5523
function DHCP_Config_File_Advanced($interface, $ifcfg, $realif) {
5524

    
5525
	$hostname = "";
5526
	if ($ifcfg['dhcphostname'] != '') {
5527
		$hostname = "\tsend host-name \"{$ifcfg['dhcphostname']}\";\n";
5528
	}
5529

    
5530
	/* DHCP Protocol Timings */
5531
	$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");
5532
	foreach ($protocol_timings as $Protocol_Timing => $PT_Name) {
5533
		$pt_variable = "{$Protocol_Timing}";
5534
		${$pt_variable} = "";
5535
		if ($ifcfg[$Protocol_Timing] != "") {
5536
			${$pt_variable} = "{$PT_Name} {$ifcfg[$Protocol_Timing]};\n";
5537
		}
5538
	}
5539

    
5540
	$send_options = "";
5541
	if ($ifcfg['adv_dhcp_send_options'] != '') {
5542
		$options = DHCP_Config_Option_Split($ifcfg['adv_dhcp_send_options']);
5543
		foreach ($options as $option) {
5544
			$send_options .= "\tsend " . trim($option) . ";\n";
5545
		}
5546
	}
5547

    
5548
	$request_options = "";
5549
	if ($ifcfg['adv_dhcp_request_options'] != '') {
5550
		$request_options = "\trequest {$ifcfg['adv_dhcp_request_options']};\n";
5551
	}
5552

    
5553
	$required_options = "";
5554
	if ($ifcfg['adv_dhcp_required_options'] != '') {
5555
		$required_options = "\trequire {$ifcfg['adv_dhcp_required_options']};\n";
5556
	}
5557

    
5558
	$option_modifiers = "";
5559
	if ($ifcfg['adv_dhcp_option_modifiers'] != '') {
5560
		$modifiers = DHCP_Config_Option_Split($ifcfg['adv_dhcp_option_modifiers']);
5561
		foreach ($modifiers as $modifier) {
5562
			$option_modifiers .= "\t" . trim($modifier) . ";\n";
5563
		}
5564
	}
5565

    
5566
	$dhclientconf  = "interface \"{$realif}\" {\n";
5567
	$dhclientconf .= "\n";
5568
	$dhclientconf .= "\tsupersede interface-mtu 0;\n";
5569
	$dhclientconf .= "# DHCP Protocol Timing Values\n";
5570
	$dhclientconf .= "{$adv_dhcp_pt_timeout}";
5571
	$dhclientconf .= "{$adv_dhcp_pt_retry}";
5572
	$dhclientconf .= "{$adv_dhcp_pt_select_timeout}";
5573
	$dhclientconf .= "{$adv_dhcp_pt_reboot}";
5574
	$dhclientconf .= "{$adv_dhcp_pt_backoff_cutoff}";
5575
	$dhclientconf .= "{$adv_dhcp_pt_initial_interval}";
5576
	$dhclientconf .= "\n";
5577
	$dhclientconf .= "# DHCP Protocol Options\n";
5578
	$dhclientconf .= "{$hostname}";
5579
	$dhclientconf .= "{$send_options}";
5580
	$dhclientconf .= "{$request_options}";
5581
	$dhclientconf .= "{$required_options}";
5582
	$dhclientconf .= "{$option_modifiers}";
5583
	$dhclientconf .= "\n";
5584
	if (is_ipaddrv4($ifcfg['dhcprejectfrom'])) {
5585
		$dhclientconf .= "reject {$ifcfg['dhcprejectfrom']};\n";
5586
	}
5587
	$dhclientconf .= "\tscript \"/usr/local/sbin/pfSense-dhclient-script\";\n";
5588
	$dhclientconf .= "}\n";
5589

    
5590
	$dhclientconf = DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5591

    
5592
	return $dhclientconf;
5593
}
5594

    
5595
function DHCP_Config_Option_Split($option_string) {
5596
	preg_match_all('/[^",]*(?:"[^"]*"[^",]*)+(?:"[^",]*)?|[^,]+/m', $option_string, $matches, PREG_PATTERN_ORDER);
5597
	return $matches ? $matches[0] : [];
5598
}
5599

    
5600
function DHCP_Config_File_Override($ifcfg, $realif) {
5601

    
5602
	$dhclientconf = @file_get_contents($ifcfg['adv_dhcp_config_file_override_path']);
5603

    
5604
	if ($dhclientconf === false) {
5605
		log_error(sprintf(gettext("Error: cannot open %s in DHCP_Config_File_Override() for reading."), $ifcfg['adv_dhcp_config_file_override_path']));
5606
		return '';
5607
	} else {
5608
		return DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf);
5609
	}
5610
}
5611

    
5612

    
5613
function DHCP_Config_File_Substitutions($ifcfg, $realif, $dhclientconf) {
5614

    
5615
	/* Apply Interface Substitutions */
5616
	$dhclientconf = str_replace("{interface}", "{$realif}", $dhclientconf);
5617

    
5618
	/* Apply Hostname Substitutions */
5619
	$dhclientconf = str_replace("{hostname}", $ifcfg['dhcphostname'], $dhclientconf);
5620

    
5621
	/* Arrays of MAC Address Types, Cases, Delimiters */
5622
	/* ASCII or HEX, Upper or Lower Case, Various Delimiters (none, space, colon, hyphen, period) */
5623
	$various_mac_types      = array("mac_addr_ascii", "mac_addr_hex");
5624
	$various_mac_cases      = array("U", "L");
5625
	$various_mac_delimiters = array("", " ", ":", "-", ".");
5626

    
5627
	/* Apply MAC Address Substitutions */
5628
	foreach ($various_mac_types as $various_mac_type) {
5629
		foreach ($various_mac_cases as $various_mac_case) {
5630
			foreach ($various_mac_delimiters as $various_mac_delimiter) {
5631

    
5632
				$res = stripos($dhclientconf, $various_mac_type . $various_mac_case . $various_mac_delimiter);
5633
				if ($res !== false) {
5634

    
5635
					/* Get MAC Address as ASCII String With Colon (:) delimiters */
5636
					if ("$various_mac_case" == "U") {
5637
						$dhcpclientconf_mac = strtoupper(get_interface_mac($realif));
5638
					}
5639
					if ("$various_mac_case" == "L") {
5640
						$dhcpclientconf_mac = strtolower(get_interface_mac($realif));
5641
					}
5642

    
5643
					if ("$various_mac_type" == "mac_addr_hex") {
5644
						/* Convert MAC ascii string to HEX with colon (:) delimiters. */
5645
						$dhcpclientconf_mac = str_replace(":", "", $dhcpclientconf_mac);
5646
						$dhcpclientconf_mac_hex = "";
5647
						$delimiter = "";
5648
						for ($i = 0; $i < strlen($dhcpclientconf_mac); $i++) {
5649
							$dhcpclientconf_mac_hex .= $delimiter. bin2hex($dhcpclientconf_mac[$i]);
5650
							$delimiter = ":";
5651
						}
5652
						$dhcpclientconf_mac = $dhcpclientconf_mac_hex;
5653
					}
5654

    
5655
					/* MAC Address Delimiter Substitutions */
5656
					$dhcpclientconf_mac = str_replace(":", $various_mac_delimiter, $dhcpclientconf_mac);
5657

    
5658
					/* Apply MAC Address Substitutions */
5659
					$dhclientconf = str_replace("{" . $various_mac_type . $various_mac_case . $various_mac_delimiter . "}", $dhcpclientconf_mac, $dhclientconf);
5660
				}
5661
			}
5662
		}
5663
	}
5664

    
5665
	return $dhclientconf;
5666
}
5667

    
5668
function interfaces_group_setup() {
5669
	global $config;
5670

    
5671
	if (!isset($config['ifgroups']['ifgroupentry']) ||
5672
	    !is_array($config['ifgroups']['ifgroupentry'])) {
5673
		return;
5674
	}
5675

    
5676
	foreach ($config['ifgroups']['ifgroupentry'] as $groupar) {
5677
		interface_group_setup($groupar);
5678
	}
5679

    
5680
	return;
5681
}
5682

    
5683
function interface_group_setup(&$groupname /* The parameter is an array */) {
5684
	global $config;
5685

    
5686
	if (!is_array($groupname)) {
5687
		return;
5688
	}
5689
	$members = explode(" ", $groupname['members']);
5690
	foreach ($members as $ifs) {
5691
		$realif = get_real_interface($ifs);
5692
		if ($realif && does_interface_exist($realif)) {
5693
			mwexec("/sbin/ifconfig {$realif} group {$groupname['ifname']}");
5694
		}
5695
	}
5696

    
5697
	return;
5698
}
5699

    
5700
function is_interface_group($if) {
5701
	global $config;
5702

    
5703
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5704
		foreach ($config['ifgroups']['ifgroupentry'] as $groupentry) {
5705
			if ($groupentry['ifname'] === $if) {
5706
				return true;
5707
			}
5708
		}
5709
	}
5710

    
5711
	return false;
5712
}
5713

    
5714
function interface_group_add_member($interface, $groupname) {
5715
	$interface = get_real_interface($interface);
5716
	if (does_interface_exist($interface)) {
5717
		mwexec("/sbin/ifconfig {$interface} group " . escapeshellarg($groupname), true);
5718
	}
5719
}
5720

    
5721
/* COMPAT Function */
5722
function convert_friendly_interface_to_real_interface_name($interface) {
5723
	return get_real_interface($interface);
5724
}
5725

    
5726
/* COMPAT Function */
5727
function get_real_wan_interface($interface = "wan") {
5728
	return get_real_interface($interface);
5729
}
5730

    
5731
/* COMPAT Function */
5732
function get_current_wan_address($interface = "wan") {
5733
	return get_interface_ip($interface);
5734
}
5735

    
5736
/*
5737
 * convert_real_interface_to_friendly_interface_name($interface): convert fxp0 -> wan, etc.
5738
 */
5739
function convert_real_interface_to_friendly_interface_name($interface = "wan", $checkparent = false) {
5740
	global $config;
5741

    
5742
	/* XXX: For speed reasons reference directly the interface array */
5743
	init_config_arr(array('interfaces'));
5744
	$ifdescrs = &$config['interfaces'];
5745
	//$ifdescrs = get_configured_interface_list(true);
5746

    
5747
	foreach ($ifdescrs as $if => $ifname) {
5748
		if ($if == $interface || $ifname['if'] == $interface) {
5749
			return $if;
5750
		}
5751

    
5752
		if (get_real_interface($if) == $interface) {
5753
			return $if;
5754
		}
5755

    
5756
		if ($checkparent == false) {
5757
			continue;
5758
		}
5759

    
5760
		$int = get_parent_interface($if, true);
5761
		if (is_array($int)) {
5762
			foreach ($int as $iface) {
5763
				if ($iface == $interface) {
5764
					return $if;
5765
				}
5766
			}
5767
		}
5768
	}
5769

    
5770
	if ($interface == "enc0") {
5771
		return 'IPsec';
5772
	}
5773
}
5774

    
5775
/* attempt to resolve interface to friendly descr */
5776
function convert_friendly_interface_to_friendly_descr($interface) {
5777
	global $config;
5778

    
5779
	switch ($interface) {
5780
		case "l2tp":
5781
			$ifdesc = "L2TP";
5782
			break;
5783
		case "pptp":
5784
			$ifdesc = "PPTP";
5785
			break;
5786
		case "pppoe":
5787
			$ifdesc = "PPPoE";
5788
			break;
5789
		case "openvpn":
5790
			$ifdesc = "OpenVPN";
5791
			break;
5792
		case "lo0":
5793
			$ifdesc = "Loopback";
5794
			break;
5795
		case "enc0":
5796
		case "ipsec":
5797
		case "IPsec":
5798
			$ifdesc = "IPsec";
5799
			break;
5800
		default:
5801
			if (isset($config['interfaces'][$interface])) {
5802
				if (empty($config['interfaces'][$interface]['descr'])) {
5803
					$ifdesc = strtoupper($interface);
5804
				} else {
5805
					$ifdesc = strtoupper($config['interfaces'][$interface]['descr']);
5806
				}
5807
				break;
5808
			} elseif (substr($interface, 0, 4) == '_vip') {
5809
				if (is_array($config['virtualip']['vip'])) {
5810
					foreach ($config['virtualip']['vip'] as $counter => $vip) {
5811
						if (($vip['mode'] == "carp") || ($vip['mode'] == "ipalias")) {
5812
							if ($interface == "_vip{$vip['uniqid']}") {
5813
								$descr = $vip['subnet'];
5814
								if (!empty($vip['vhid'])) {
5815
									$descr .= " (vhid {$vip['vhid']})";
5816
								}
5817
								if (!empty($vip['descr'])) {
5818
									$descr .= " - " .$vip['descr'];
5819
								}
5820
								return $descr;
5821
							}
5822
						}
5823
					}
5824
				}
5825
			} elseif (substr($interface, 0, 5) == '_lloc') {
5826
				return get_interface_linklocal($interface);
5827
			} else {
5828
				if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
5829
					foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
5830
						if ($ifgen['ifname'] === $interface) {
5831
							return $ifgen['ifname'];
5832
						}
5833
					}
5834
				}
5835

    
5836
				/* if list */
5837
				$ifdescrs = get_configured_interface_with_descr(true);
5838
				foreach ($ifdescrs as $if => $ifname) {
5839
					if ($if == $interface || $ifname == $interface) {
5840
						return $ifname;
5841
					}
5842
				}
5843
			}
5844
			break;
5845
	}
5846

    
5847
	return $ifdesc;
5848
}
5849

    
5850
function convert_real_interface_to_friendly_descr($interface) {
5851

    
5852
	$ifdesc = convert_real_interface_to_friendly_interface_name("{$interface}");
5853

    
5854
	if (!empty($ifdesc)) {
5855
		return convert_friendly_interface_to_friendly_descr($ifdesc);
5856
	}
5857

    
5858
	return $interface;
5859
}
5860

    
5861
/*
5862
 *  get_parent_interface($interface):
5863
 *			--returns the (real or virtual) parent interface(s) array for a given interface friendly name (i.e. wan)
5864
 *				or virtual interface (i.e. vlan)
5865
 *				(We need array because MLPPP and bridge interfaces have more than one parent.)
5866
 *			-- returns $interface passed in if $interface parent is not found
5867
 *			-- returns empty array if an invalid interface is passed
5868
 *	(Only handles ppps and vlans now.)
5869
 */
5870
function get_parent_interface($interface, $avoidrecurse = false) {
5871
	global $config;
5872

    
5873
	$parents = array();
5874
	//Check that we got a valid interface passed
5875
	$realif = get_real_interface($interface);
5876
	if ($realif == NULL) {
5877
		return $parents;
5878
	}
5879

    
5880
	// If we got a real interface, find it's friendly assigned name
5881
	if ($interface == $realif && $avoidrecurse == false) {
5882
		$interface = convert_real_interface_to_friendly_interface_name($interface);
5883
	}
5884

    
5885
	if (!empty($interface) && isset($config['interfaces'][$interface])) {
5886
		$ifcfg = $config['interfaces'][$interface];
5887
		switch ($ifcfg['ipaddr']) {
5888
			case "ppp":
5889
			case "pppoe":
5890
			case "pptp":
5891
			case "l2tp":
5892
				if (empty($parents)) {
5893
					if (is_array($config['ppps']['ppp'])) {
5894
						foreach ($config['ppps']['ppp'] as $pppidx => $ppp) {
5895
							if ($ifcfg['if'] == $ppp['if']) {
5896
								$ports = explode(',', $ppp['ports']);
5897
								foreach ($ports as $pid => $parent_if) {
5898
									$parents[$pid] = get_real_interface($parent_if);
5899
								}
5900
								break;
5901
							}
5902
						}
5903
					}
5904
				}
5905
				break;
5906
			case "dhcp":
5907
			case "static":
5908
			default:
5909
				// Handle _vlans
5910
				$vlan = interface_is_vlan($ifcfg['if']);
5911
				if ($vlan != NULL) {
5912
					$parents[0] = $vlan['if'];
5913
				}
5914
				break;
5915
		}
5916
	}
5917

    
5918
	if (empty($parents)) {
5919
		// Handle _vlans not assigned to an interface
5920
		$vlan = interface_is_vlan($realif);
5921
		if ($vlan != NULL) {
5922
			$parents[0] = $vlan['if'];
5923
		}
5924
	}
5925

    
5926
	if (empty($parents)) {
5927
		/* Handle LAGGs. */
5928
		$lagg = interface_is_type($realif, 'lagg');
5929
		if ($lagg != NULL && isset($lagg['members'])) {
5930
			$parents = explode(",", $lagg['members']);
5931
		}
5932
	}
5933

    
5934
	if (empty($parents)) {
5935
		$parents[0] = $realif;
5936
	}
5937

    
5938
	return $parents;
5939
}
5940

    
5941
/*
5942
 *  get_parent_physical_interface($interface):
5943
 *   - returns an array of parent interface(s) for a given interface friendly name (e.g. wan)
5944
 *  differs from get_parent_interface in that it traverses to find the physical NICs on lagg
5945
 */
5946
function get_parent_physical_interface($interface) {
5947
	global $config;
5948

    
5949
	$realif = get_parent_interface($interface);
5950

    
5951
	if (substr($realif[0], 0, 4) == "lagg") {
5952
		foreach ($config['laggs']['lagg'] as $lagg) {
5953
			if ($realif[0] == $lagg['laggif']) {
5954
				return explode(",", $lagg['members']);
5955
			}
5956
		}
5957
	} else {
5958
		return $realif;
5959
	}
5960
}
5961

    
5962
function interface_is_wireless_clone($wlif) {
5963
	if (!stristr($wlif, "_wlan")) {
5964
		return false;
5965
	} else {
5966
		return true;
5967
	}
5968
}
5969

    
5970
function interface_get_wireless_base($wlif) {
5971
	if (!stristr($wlif, "_wlan")) {
5972
		return $wlif;
5973
	} else {
5974
		return substr($wlif, 0, stripos($wlif, "_wlan"));
5975
	}
5976
}
5977

    
5978
function interface_get_wireless_clone($wlif) {
5979
	if (!stristr($wlif, "_wlan")) {
5980
		return $wlif . "_wlan0";
5981
	} else {
5982
		return $wlif;
5983
	}
5984
}
5985

    
5986
function interface_list_wireless() {
5987
	$portlist = explode(" ", get_single_sysctl("net.wlan.devices"));
5988

    
5989
	$result = array();
5990
	foreach ($portlist as $port) {
5991
		if (preg_match("/^([^0-9]+)([0-9]+)/", $port, $matches) != 1) {
5992
			continue;
5993
		}
5994

    
5995
		$desc = $port . " ( " . get_single_sysctl(
5996
		    "dev.{$matches[1]}.{$matches[2]}.%desc") . " )";
5997

    
5998
		$result[] = array(
5999
		    "if" => $port,
6000
		    "descr" => $desc
6001
		);
6002
	}
6003

    
6004
	return $result;
6005
}
6006

    
6007
function get_real_interface($interface = "wan", $family = "all", $realv6iface = false, $flush = false) {
6008
	global $config, $g;
6009

    
6010
	$wanif = NULL;
6011

    
6012
	switch ($interface) {
6013
		case "l2tp":
6014
			$wanif = "l2tp";
6015
			break;
6016
		case "pptp":
6017
			$wanif = "pptp";
6018
			break;
6019
		case "pppoe":
6020
			$wanif = "pppoe";
6021
			break;
6022
		case "openvpn":
6023
			$wanif = "openvpn";
6024
			break;
6025
		case "IPsec":
6026
		case "ipsec":
6027
		case "enc0":
6028
			$wanif = "enc0";
6029
			break;
6030
		case "ppp":
6031
			$wanif = "ppp";
6032
			break;
6033
		default:
6034
			if (substr($interface, 0, 4) == '_vip') {
6035
				$wanif = get_configured_vip_interface($interface);
6036
				if (!empty($wanif)) {
6037
					$wanif = get_real_interface($wanif);
6038
				}
6039
				break;
6040
			} elseif (substr($interface, 0, 5) == '_lloc') {
6041
				$interface = substr($interface, 5);
6042
			} elseif (interface_is_vlan($interface) != NULL ||
6043
			    does_interface_exist($interface, $flush)) {
6044
				/*
6045
				 * If a real interface was already passed simply
6046
				 * pass the real interface back.  This encourages
6047
				 * the usage of this function in more cases so that
6048
				 * we can combine logic for more flexibility.
6049
				 */
6050
				$wanif = $interface;
6051
				break;
6052
			}
6053

    
6054
			if (empty($config['interfaces'][$interface])) {
6055
				break;
6056
			}
6057

    
6058
			$cfg = &$config['interfaces'][$interface];
6059

    
6060
			if ($family == "inet6") {
6061
				switch ($cfg['ipaddrv6']) {
6062
					case "6rd":
6063
					case "6to4":
6064
						$wanif = "{$interface}_stf";
6065
						break;
6066
					case 'pppoe':
6067
					case 'ppp':
6068
					case 'l2tp':
6069
					case 'pptp':
6070
						if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6071
							$wanif = interface_get_wireless_clone($cfg['if']);
6072
						} else {
6073
							$wanif = $cfg['if'];
6074
						}
6075
						break;
6076
					default:
6077
						switch ($cfg['ipaddr']) {
6078
							case 'pppoe':
6079
							case 'ppp':
6080
							case 'l2tp':
6081
							case 'pptp':
6082
								// Added catch for static v6 but using v4 link. Sets things to use pppoe link
6083
								if ((isset($cfg['dhcp6usev4iface']) && $realv6iface === false) ||
6084
								    isset($cfg['ipv6usev4iface']) || isset($cfg['slaacusev4iface'])) {
6085
									$wanif = $cfg['if'];
6086
								} else {
6087
									$parents = get_parent_interface($interface);
6088
									if (!empty($parents[0])) {
6089
										$wanif = $parents[0];
6090
									} else {
6091
										$wanif = $cfg['if'];
6092
									}
6093
								}
6094
								break;
6095
							default:
6096
								if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6097
									$wanif = interface_get_wireless_clone($cfg['if']);
6098
								} else {
6099
									$wanif = $cfg['if'];
6100
								}
6101
								break;
6102
						}
6103
						break;
6104
				}
6105
			} else {
6106
				// Wireless cloned NIC support (FreeBSD 8+)
6107
				// interface name format: $parentnic_wlanparentnic#
6108
				// example: ath0_wlan0
6109
				if (is_array($cfg['wireless']) || preg_match($g['wireless_regex'], $cfg['if'])) {
6110
					$wanif = interface_get_wireless_clone($cfg['if']);
6111
				} else {
6112
					$wanif = $cfg['if'];
6113
				}
6114
			}
6115
			break;
6116
	}
6117

    
6118
	return $wanif;
6119
}
6120

    
6121
/* Guess the physical interface by providing a IP address */
6122
function guess_interface_from_ip($ipaddress) {
6123

    
6124
	if (!is_ipaddr($ipaddress)) {
6125
		return false;
6126
	}
6127

    
6128
	$route = route_get($ipaddress, '', true);
6129
	if (empty($route)) {
6130
		return false;
6131
	}
6132

    
6133
	if (!empty($route[0]['interface-name'])) {
6134
		return $route[0]['interface-name'];
6135
	}
6136

    
6137
	return false;
6138
}
6139

    
6140
/*
6141
 * find_ip_interface($ip): return the interface where an ip is defined
6142
 *   (or if $bits is specified, where an IP within the subnet is defined)
6143
 */
6144
function find_ip_interface($ip, $bits = null) {
6145
	if (!is_ipaddr($ip)) {
6146
		return false;
6147
	}
6148

    
6149
	$isv6ip = is_ipaddrv6($ip);
6150

    
6151
	/* if list */
6152
	$ifdescrs = get_configured_interface_list();
6153

    
6154
	foreach ($ifdescrs as $ifdescr => $ifname) {
6155
		$ifip = ($isv6ip) ? get_interface_ipv6($ifname) : get_interface_ip($ifname);
6156
		if (is_null($ifip)) {
6157
			continue;
6158
		}
6159
		if (is_null($bits)) {
6160
			if ($ip == $ifip) {
6161
				$int = get_real_interface($ifname);
6162
				return $int;
6163
			}
6164
		} else {
6165
			if (ip_in_subnet($ifip, $ip . "/" . $bits)) {
6166
				$int = get_real_interface($ifname);
6167
				return $int;
6168
			}
6169
		}
6170
	}
6171

    
6172
	return false;
6173
}
6174

    
6175
/*
6176
 * find_virtual_ip_alias($ip): return the virtual IP alias where an IP is found
6177
 *   (or if $bits is specified, where an IP within the subnet is found)
6178
 */
6179
function find_virtual_ip_alias($ip, $bits = null) {
6180
	global $config;
6181

    
6182
	if (!is_array($config['virtualip']['vip'])) {
6183
		return false;
6184
	}
6185
	if (!is_ipaddr($ip)) {
6186
		return false;
6187
	}
6188

    
6189
	$isv6ip = is_ipaddrv6($ip);
6190

    
6191
	foreach ($config['virtualip']['vip'] as $vip) {
6192
		if ($vip['mode'] === "ipalias") {
6193
			if (is_ipaddrv6($vip['subnet']) != $isv6ip) {
6194
				continue;
6195
			}
6196
			if (is_null($bits)) {
6197
				if (ip_in_subnet($ip, $vip['subnet'] . "/" . $vip['subnet_bits'])) {
6198
					return $vip;
6199
				}
6200
			} else {
6201
				if (($isv6ip && check_subnetsv6_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits'])) ||
6202
				    (!$isv6ip && check_subnets_overlap($ip, $bits, $vip['subnet'], $vip['subnet_bits']))) {
6203
					return $vip;
6204
				}
6205
			}
6206
		}
6207
	}
6208
	return false;
6209
}
6210

    
6211
function link_interface_to_track6($int, $action = "") {
6212
	global $config;
6213

    
6214
	if (empty($int)) {
6215
		return;
6216
	}
6217

    
6218
	if (is_array($config['interfaces'])) {
6219
		$list = array();
6220
		foreach ($config['interfaces'] as $ifname => $ifcfg) {
6221
			if (!isset($ifcfg['enable'])) {
6222
				continue;
6223
			}
6224
			if (!empty($ifcfg['ipaddrv6']) && $ifcfg['track6-interface'] == $int) {
6225
				if ($action == "update") {
6226
					interface_track6_configure($ifname, $ifcfg);
6227
				} elseif ($action == "") {
6228
					$list[$ifname] = $ifcfg;
6229
				}
6230
			}
6231
		}
6232
		return $list;
6233
	}
6234
}
6235

    
6236
function interface_find_child_cfgmtu($realiface) {
6237
	global $config;
6238

    
6239
	$interface = convert_real_interface_to_friendly_interface_name($realiface);
6240
	$vlans = link_interface_to_vlans($realiface);
6241
	$qinqs = link_interface_to_qinqs($realiface);
6242
	$bridge = link_interface_to_bridge($realiface);
6243
	$gifs = link_interface_to_tunnelif($interface, 'gif');
6244
	$gres = link_interface_to_tunnelif($interface, 'gre');
6245

    
6246
	$mtu = 0;
6247
	if (is_array($vlans)) {
6248
		foreach ($vlans as $vlan) {
6249
			$ifass = convert_real_interface_to_friendly_interface_name($vlan['vlanif']);
6250
			if (empty($ifass)) {
6251
				continue;
6252
			}
6253
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6254
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6255
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6256
				}
6257
			}
6258
		}
6259
	}
6260
	if (is_array($qinqs)) {
6261
		foreach ($qinqs as $qinq) {
6262
			$ifass = convert_real_interface_to_friendly_interface_name($qinq['vlanif']);
6263
			if (empty($ifass)) {
6264
				continue;
6265
			}
6266
			if (!empty($config['interfaces'][$ifass]['mtu'])) {
6267
				if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6268
					$mtu = intval($config['interfaces'][$ifass]['mtu']);
6269
				}
6270
			}
6271
		}
6272
	}
6273
	foreach ($gifs as $gif) {
6274
		$ifass = convert_real_interface_to_friendly_interface_name($gif['gifif']);
6275
		if (empty($ifass)) {
6276
			continue;
6277
		}
6278
		if (!empty($config['interfaces'][$ifass]['mtu'])) {
6279
			if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6280
				$mtu = intval($config['interfaces'][$ifass]['mtu']);
6281
			}
6282
		}
6283
	}
6284
	foreach ($gres as $gre) {
6285
		$ifass = convert_real_interface_to_friendly_interface_name($gre['greif']);
6286
		if (empty($ifass)) {
6287
			continue;
6288
		}
6289
		if (!empty($config['interfaces'][$ifass]['mtu'])) {
6290
			if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6291
				$mtu = intval($config['interfaces'][$ifass]['mtu']);
6292
			}
6293
		}
6294
	}
6295
	$ifass = convert_real_interface_to_friendly_interface_name($bridge);
6296
	if (!empty($ifass) && !empty($config['interfaces'][$ifass]['mtu'])) {
6297
		if (intval($config['interfaces'][$ifass]['mtu']) > $mtu) {
6298
			$mtu = intval($config['interfaces'][$ifass]['mtu']);
6299
		}
6300
	}
6301
	unset($vlans, $bridge, $gifs, $gres, $ifass, $vlan);
6302

    
6303
	return $mtu;
6304
}
6305

    
6306
function link_interface_to_vlans($int, $action = "") {
6307
	global $config;
6308

    
6309
	if (empty($int)) {
6310
		return;
6311
	}
6312

    
6313
	if (is_array($config['vlans']['vlan'])) {
6314
		$ifaces = array();
6315
		foreach ($config['vlans']['vlan'] as $vlan) {
6316
			if ($int == $vlan['if']) {
6317
				if ($action == "update") {
6318
					interfaces_bring_up($int);
6319
				} else {
6320
					$ifaces[$vlan['tag']] = $vlan;
6321
				}
6322
			}
6323
		}
6324
		if (!empty($ifaces)) {
6325
			return $ifaces;
6326
		}
6327
	}
6328
}
6329

    
6330
function link_interface_to_qinqs($int, $action = "") {
6331
	global $config;
6332

    
6333
	if (empty($int)) {
6334
		return;
6335
	}
6336

    
6337
	if (is_array($config['qinqs']['qinqentry'])) {
6338
		$ifaces = array();
6339
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
6340
			if ($int == $qinq['if']) {
6341
				if ($action == "update") {
6342
					interfaces_bring_up($int);
6343
				} else {
6344
					$ifaces[$qinq['tag']] = $qinq;
6345
				}
6346
			}
6347
		}
6348
		if (!empty($ifaces)) {
6349
			return $ifaces;
6350
		}
6351
	}
6352
}
6353

    
6354
function link_interface_to_vips($int, $action = "", $vhid = '') {
6355
	global $config;
6356

    
6357
	$updatevips = false;
6358
	if (is_array($config['virtualip']['vip'])) {
6359
		$result = array();
6360
		foreach ($config['virtualip']['vip'] as $vip) {
6361
			if (substr($vip['interface'], 0, 4) == "_vip") {
6362
				$iface = get_configured_vip_interface($vip['interface']);
6363
			} else {
6364
				$iface = $vip['interface'];
6365
			}
6366
			if ($int != $iface) {
6367
				continue;
6368
			}
6369
			if ($action == "update") {
6370
				$updatevips = true;
6371
			} else {
6372
				if (empty($vhid) || ($vhid == $vip['vhid']) ||
6373
				    substr($vip['interface'], 0, 4) == "_vip") {
6374
					$result[] = $vip;
6375
				}
6376
			}
6377
		}
6378
		if ($updatevips === true) {
6379
			interfaces_vips_configure($int);
6380
		}
6381
		return $result;
6382
	}
6383

    
6384
	return NULL;
6385
}
6386

    
6387
/****f* interfaces/link_interface_to_bridge
6388
 * NAME
6389
 *   link_interface_to_bridge - Finds out a bridge group for an interface
6390
 * INPUTS
6391
 *   $ip
6392
 * RESULT
6393
 *   bridge[0-99]
6394
 ******/
6395
function link_interface_to_bridge($int) {
6396
	global $config;
6397

    
6398
	if (isset($config['bridges']['bridged']) && is_array($config['bridges']['bridged'])) {
6399
		foreach ($config['bridges']['bridged'] as $bridge) {
6400
			if (in_array($int, explode(',', $bridge['members']))) {
6401
				return "{$bridge['bridgeif']}";
6402
			}
6403
		}
6404
	}
6405
}
6406

    
6407
function link_interface_to_lagg($int) {
6408
	global $config;
6409

    
6410
	if (isset($config['laggs']['lagg']) && is_array($config['laggs']['lagg'])) {
6411
		foreach ($config['laggs']['lagg'] as $lagg) {
6412
			if (in_array($int, explode(',', $lagg['members']))) {
6413
				return "{$lagg['laggif']}";
6414
			}
6415
		}
6416
	}
6417
}
6418

    
6419
function link_interface_to_group($int) {
6420
	global $config;
6421

    
6422
	$result = array();
6423

    
6424
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
6425
		foreach ($config['ifgroups']['ifgroupentry'] as $group) {
6426
			if (in_array($int, explode(" ", $group['members']))) {
6427
				$result[$group['ifname']] = $int;
6428
			}
6429
		}
6430
	}
6431

    
6432
	return $result;
6433
}
6434

    
6435
function link_interface_to_tunnelif($interface, $type, $remote = 'any') {
6436
	global $config;
6437

    
6438
	$result = array();
6439

    
6440
	if (empty($interface)) {
6441
		return $result;
6442
	}
6443

    
6444
	if (!in_array($type, array('gre', 'gif'))) {
6445
		return $result;
6446
	}
6447

    
6448
	if (is_array($config["{$type}s"][$type])) {
6449
		foreach ($config["{$type}s"][$type] as $tunnel) {
6450
			if (($tunnel['if'] == $interface) && (($remote == 'any') ||
6451
			    (is_ipaddrv4($tunnel['remote-addr']) && ($remote == 'inet')) ||
6452
			    (is_ipaddrv6($tunnel['remote-addr']) && ($remote == 'inet6')))) { 
6453
				$result[] = $tunnel;
6454
			}
6455
		}
6456
	}
6457

    
6458
	return $result;
6459
}
6460

    
6461
function link_interface_to_ppp_tunnelif($interface) {
6462
	global $config;
6463

    
6464
	$result = array();
6465

    
6466
	if (empty($interface)) {
6467
		return $result;
6468
	}
6469

    
6470
	init_config_arr(array('ppps', 'ppp'));
6471
	if (!empty($config['ppps']['ppp'])) {
6472
		$realif = get_real_interface($interface);
6473
		foreach ($config['ppps']['ppp'] as $ppp) {
6474
			if (($ppp['ports'] == $realif) && in_array($ppp['type'], array('l2tp', 'pptp'))) { 
6475
				$result[] = $ppp;
6476
			}
6477
		}
6478
	}
6479

    
6480
	return $result;
6481
}
6482

    
6483
/*
6484
 * find_interface_ip($interface): return the interface ip (first found)
6485
 */
6486
function find_interface_ip($interface, $flush = false) {
6487
	global $interface_ip_arr_cache;
6488
	global $interface_sn_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_ip_arr_cache[$interface]) or $flush) {
6498
		if (file_exists("/var/db/${interface}_ip")) {
6499
			$ifip = chop(file_get_contents("/var/db/${interface}_ip"));
6500
			$ifaddrs = pfSense_getall_interface_addresses($interface);
6501
			foreach ($ifaddrs as $ifaddr) {
6502
				list($ip, $mask) = explode("/", $ifaddr);
6503
				if ($ip == $ifip) {
6504
					$interface_ip_arr_cache[$interface] = $ip;
6505
					$interface_sn_arr_cache[$interface] = $mask;
6506
					break;
6507
				}
6508
			}
6509
		}
6510
		if (!isset($interface_ip_arr_cache[$interface])) {
6511
			$ifinfo = pfSense_get_interface_addresses($interface);
6512
			$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6513
			$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6514
		}
6515
	}
6516

    
6517
	return $interface_ip_arr_cache[$interface];
6518
}
6519

    
6520
/*
6521
 * find_interface_ipv6($interface): return the interface ip (first found)
6522
 */
6523
function find_interface_ipv6($interface, $flush = false) {
6524
	global $interface_ipv6_arr_cache;
6525
	global $interface_snv6_arr_cache;
6526
	global $config;
6527

    
6528
	$interface = trim($interface);
6529
	$interface = get_real_interface($interface);
6530

    
6531
	if (!does_interface_exist($interface)) {
6532
		return;
6533
	}
6534

    
6535
	/* Setup IP cache */
6536
	if (!isset($interface_ipv6_arr_cache[$interface]) or $flush) {
6537
		$ifinfo = pfSense_get_interface_addresses($interface);
6538
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6539
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6540
	}
6541

    
6542
	return $interface_ipv6_arr_cache[$interface];
6543
}
6544

    
6545
/*
6546
 * find_interface_ipv6_ll($interface): return the interface ipv6 link local (first found)
6547
 */
6548
function find_interface_ipv6_ll($interface, $flush = false) {
6549
	global $interface_llv6_arr_cache;
6550
	global $config;
6551

    
6552
	$interface = str_replace("\n", "", $interface);
6553

    
6554
	if (!does_interface_exist($interface)) {
6555
		return;
6556
	}
6557

    
6558
	/* Setup IP cache */
6559
	if (!isset($interface_llv6_arr_cache[$interface]) or $flush) {
6560
		$ifinfo = pfSense_getall_interface_addresses($interface);
6561
		foreach ($ifinfo as $line) {
6562
			if (strstr($line, ":")) {
6563
				$parts = explode("/", $line);
6564
				if (is_linklocal($parts[0])) {
6565
					$ifinfo['linklocal'] = $parts[0];
6566
				}
6567
			}
6568
		}
6569
		$interface_llv6_arr_cache[$interface] = $ifinfo['linklocal'];
6570
	}
6571
	return $interface_llv6_arr_cache[$interface];
6572
}
6573

    
6574
function find_interface_subnet($interface, $flush = false) {
6575
	global $interface_sn_arr_cache;
6576
	global $interface_ip_arr_cache;
6577

    
6578
	$interface = str_replace("\n", "", $interface);
6579
	if (does_interface_exist($interface) == false) {
6580
		return;
6581
	}
6582

    
6583
	if (!isset($interface_sn_arr_cache[$interface]) or $flush) {
6584
		$ifinfo = pfSense_get_interface_addresses($interface);
6585
		$interface_ip_arr_cache[$interface] = $ifinfo['ipaddr'];
6586
		$interface_sn_arr_cache[$interface] = $ifinfo['subnetbits'];
6587
	}
6588

    
6589
	return $interface_sn_arr_cache[$interface];
6590
}
6591

    
6592
function find_interface_subnetv6($interface, $flush = false) {
6593
	global $interface_snv6_arr_cache;
6594
	global $interface_ipv6_arr_cache;
6595

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

    
6601
	if (!isset($interface_snv6_arr_cache[$interface]) or $flush) {
6602
		$ifinfo = pfSense_get_interface_addresses($interface);
6603
		$interface_ipv6_arr_cache[$interface] = $ifinfo['ipaddr6'];
6604
		$interface_snv6_arr_cache[$interface] = $ifinfo['subnetbits6'];
6605
	}
6606

    
6607
	return $interface_snv6_arr_cache[$interface];
6608
}
6609

    
6610
function ip_in_interface_alias_subnet($interface, $ipalias) {
6611
	global $config;
6612

    
6613
	if (empty($interface) || !is_ipaddr($ipalias)) {
6614
		return false;
6615
	}
6616
	if (is_array($config['virtualip']['vip'])) {
6617
		foreach ($config['virtualip']['vip'] as $vip) {
6618
			switch ($vip['mode']) {
6619
				case "ipalias":
6620
					if ($vip['interface'] <> $interface) {
6621
						break;
6622
					}
6623
					$subnet = is_ipaddrv6($ipalias) ? gen_subnetv6($vip['subnet'], $vip['subnet_bits']) : gen_subnet($vip['subnet'], $vip['subnet_bits']);
6624
					if (ip_in_subnet($ipalias, $subnet . "/" . $vip['subnet_bits'])) {
6625
						return true;
6626
					}
6627
					break;
6628
			}
6629
		}
6630
	}
6631

    
6632
	return false;
6633
}
6634

    
6635
function get_possible_listen_ips($include_ipv6_link_local=false) {
6636

    
6637
	$interfaces = get_configured_interface_with_descr();
6638
	foreach ($interfaces as $iface => $ifacename) {
6639
		if ($include_ipv6_link_local) {
6640
			/* This is to avoid going though added ll below */
6641
			if (substr($iface, 0, 5) == '_lloc') {
6642
				continue;
6643
			}
6644
			$llip = find_interface_ipv6_ll(get_real_interface($iface));
6645
			if (!empty($llip)) {
6646
				$interfaces["_lloc{$iface}"] = "{$ifacename} IPv6 Link-Local";
6647
			}
6648
		}
6649
	}
6650
	$viplist = get_configured_vip_list();
6651
	foreach ($viplist as $vip => $address) {
6652
		$interfaces[$vip] = $address;
6653
		if (get_vip_descr($address)) {
6654
			$interfaces[$vip] .= " (". get_vip_descr($address) .")";
6655
		}
6656
	}
6657

    
6658
	$interfaces['lo0'] = 'Localhost';
6659

    
6660
	return $interfaces;
6661
}
6662

    
6663
function get_possible_traffic_source_addresses($include_ipv6_link_local=false) {
6664
	global $config;
6665

    
6666
	$sourceips = get_possible_listen_ips($include_ipv6_link_local);
6667
	foreach (array('server', 'client') as $mode) {
6668
		if (is_array($config['openvpn']["openvpn-{$mode}"])) {
6669
			foreach ($config['openvpn']["openvpn-{$mode}"] as $id => $setting) {
6670
				if (!isset($setting['disable'])) {
6671
					$sourceips_key = 'ovpn' . substr($mode, 0, 1) . $setting['vpnid'];
6672
					$sourceips[$sourceips_key] = gettext("OpenVPN") . " " . $mode . ": " . htmlspecialchars($setting['description']);
6673
				}
6674
			}
6675
		}
6676
	}
6677

    
6678
	init_config_arr(array('ipsec', 'phase1'));
6679
	foreach ($config['ipsec']['phase1'] as $p1) {
6680
		if ($p1['disabled']) {
6681
			continue;
6682
		}
6683
		if (ipsec_vti($p1)) {
6684
			$vtiiflist = interface_ipsec_vti_list_p1($p1);
6685
			if (!empty($vtiiflist)) {
6686
				$sourceips = array_merge($sourceips, $vtiiflist);
6687
			}
6688
		}
6689
	}
6690
	return $sourceips;
6691
}
6692

    
6693
function get_interface_ip($interface = "wan", $gateways_status = false) {
6694
	global $config;
6695

    
6696
	if (substr($interface, 0, 4) == '_vip') {
6697
		return get_configured_vip_ipv4($interface);
6698
	} elseif (substr($interface, 0, 5) == '_lloc') {
6699
		/* No link-local address for v4. */
6700
		return null;
6701
	}
6702

    
6703
	$realif = get_failover_interface($interface, 'inet', $gateways_status);
6704
	if (!$realif) {
6705
		return null;
6706
	}
6707

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

    
6715
	if (is_array($config['interfaces'][$interface]) &&
6716
	    is_ipaddr($config['interfaces'][$interface]['ipaddr'])) {
6717
		return ($config['interfaces'][$interface]['ipaddr']);
6718
	}
6719

    
6720
	/*
6721
	 * Beaware that find_interface_ip() is our last option, it will
6722
	 * return the first IP it find on interface, not necessarily the
6723
	 * main IP address.
6724
	 */
6725
	$curip = find_interface_ip($realif);
6726
	if ($curip && is_ipaddr($curip) && ($curip != "0.0.0.0")) {
6727
		return $curip;
6728
	} else {
6729
		return null;
6730
	}
6731
}
6732

    
6733
function get_interface_ipv6($interface = "wan", $flush = false, $linklocal_fallback = false, $gateways_status = false) {
6734
	global $config;
6735

    
6736
	if (substr($interface, 0, 4) == '_vip') {
6737
		return get_configured_vip_ipv6($interface);
6738
	} elseif (substr($interface, 0, 5) == '_lloc') {
6739
		return get_interface_linklocal($interface);
6740
	}
6741

    
6742
	$realif = get_failover_interface($interface, 'inet6', $gateways_status);
6743
	if (!$realif) {
6744
		return null;
6745
	}
6746

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

    
6753
	if (is_array($config['interfaces'][$interface])) {
6754
		switch ($config['interfaces'][$interface]['ipaddr']) {
6755
			case 'pppoe':
6756
			case 'l2tp':
6757
			case 'pptp':
6758
			case 'ppp':
6759
				if (($config['interfaces'][$interface]['ipaddrv6'] == 'dhcp6') ||
6760
				    ($config['interfaces'][$interface]['ipaddrv6'] == 'slaac')) {
6761
					$realif = get_real_interface($interface, 'inet6', false);
6762
				}
6763
				break;
6764
		}
6765
		if (is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6766
			return ($config['interfaces'][$interface]['ipaddrv6']);
6767
		}
6768
	}
6769

    
6770
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6771
	$checkif = is_array($config['interfaces'][$interface]) ? $interface : convert_real_interface_to_friendly_interface_name($interface);
6772
	if (is_array($config['interfaces'][$checkif]) && ($config['interfaces'][$checkif]['ipaddrv6'] == 'track6')) { 
6773
		$curip = get_interface_track6ip($checkif);
6774
		if ($curip) {
6775
			return $curip[0];
6776
		}
6777
	}
6778

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

    
6802
function get_interface_linklocal($interface = "wan") {
6803

    
6804
	$realif = get_failover_interface($interface, 'inet6');
6805
	if (!$realif) {
6806
		return null;
6807
	}
6808

    
6809
	if (substr($interface, 0, 4) == '_vip') {
6810
		$realif = get_real_interface($interface);
6811
	} elseif (substr($interface, 0, 5) == '_lloc') {
6812
		$realif = get_real_interface(substr($interface, 5));
6813
	}
6814

    
6815
	$curip = find_interface_ipv6_ll($realif);
6816
	if ($curip && is_ipaddrv6($curip) && ($curip != "::")) {
6817
		return $curip;
6818
	} else {
6819
		return null;
6820
	}
6821
}
6822

    
6823
function get_interface_track6ip($interface = "wan") {
6824
	$realif = get_real_interface($interface);
6825
	$vips = get_configured_vip_list('inet6');
6826

    
6827
	foreach (pfSense_getall_interface_addresses($realif) as $ifaddr) {
6828
		list($ip, $bits) = explode("/", $ifaddr);
6829
		$ip = text_to_compressed_ip6($ip);
6830
		if (is_ipaddrv6($ip) && !is_linklocal($ip)) {
6831
			if (is_array($vips) && !empty($vips)) {
6832
				foreach ($vips as $vip) {
6833
					if ($ip == text_to_compressed_ip6($vip)) {
6834
						continue 2;
6835
					}
6836
				}
6837
			}
6838
			return array($ip, $bits);
6839
		}
6840
	}
6841
	return false;
6842
}
6843

    
6844
function get_interface_subnet($interface = "wan") {
6845
	global $config;
6846

    
6847
	if (substr($interface, 0, 4) == '_vip') {
6848
		return (get_configured_vip_subnetv4($interface));
6849
	}
6850

    
6851
	if (is_array($config['interfaces'][$interface]) &&
6852
	    !empty($config['interfaces'][$interface]['subnet']) &&
6853
	    is_ipaddrv4($config['interfaces'][$interface]['ipaddr'])) {
6854
		return ($config['interfaces'][$interface]['subnet']);
6855
	}
6856

    
6857
	$realif = get_real_interface($interface);
6858
	if (!$realif) {
6859
		return (NULL);
6860
	}
6861

    
6862
	$cursn = find_interface_subnet($realif);
6863
	if (!empty($cursn)) {
6864
		return ($cursn);
6865
	}
6866

    
6867
	return (NULL);
6868
}
6869

    
6870
function get_interface_subnetv6($interface = "wan") {
6871
	global $config;
6872

    
6873
	if (substr($interface, 0, 4) == '_vip') {
6874
		return (get_configured_vip_subnetv6($interface));
6875
	} elseif (substr($interface, 0, 5) == '_lloc') {
6876
		$interface = substr($interface, 5);
6877
	}
6878

    
6879
	if (is_array($config['interfaces'][$interface]) &&
6880
	    !empty($config['interfaces'][$interface]['subnetv6']) &&
6881
	    is_ipaddrv6($config['interfaces'][$interface]['ipaddrv6'])) {
6882
		return ($config['interfaces'][$interface]['subnetv6']);
6883
	}
6884

    
6885
	$realif = get_real_interface($interface, 'inet6');
6886
	if (!$realif) {
6887
		return (NULL);
6888
	}
6889

    
6890
	/* try to find track6 address, see https://redmine.pfsense.org/issues/5999 */
6891
	if ($config['interfaces'][$interface]['ipaddrv6'] == 'track6') {
6892
		$curip = get_interface_track6ip($interface);
6893
		if ($curip) {
6894
			return $curip[1];
6895
		}
6896
	}
6897

    
6898
	$cursn = find_interface_subnetv6($realif);
6899
	if (!empty($cursn)) {
6900
		return ($cursn);
6901
	}
6902

    
6903
	return (NULL);
6904
}
6905

    
6906
/* return outside interfaces with a gateway */
6907
function get_interfaces_with_gateway() {
6908
	global $config;
6909

    
6910
	$ints = array();
6911

    
6912
	/* loop interfaces, check config for outbound */
6913
	foreach ($config['interfaces'] as $ifdescr => $ifname) {
6914
		switch ($ifname['ipaddr']) {
6915
			case "dhcp":
6916
			case "pppoe":
6917
			case "pptp":
6918
			case "l2tp":
6919
			case "ppp":
6920
				$ints[$ifdescr] = $ifdescr;
6921
				break;
6922
			default:
6923
				if (substr($ifname['if'], 0, 4) == "ovpn" ||
6924
				    !empty($ifname['gateway'])) {
6925
					$ints[$ifdescr] = $ifdescr;
6926
				} elseif (substr($ifname['if'], 0, 5) == "ipsec" ||
6927
				    !empty($ifname['gateway'])) {
6928
					$ints[$ifdescr] = $ifdescr;
6929
				}
6930

    
6931
				break;
6932
		}
6933
	}
6934
	return $ints;
6935
}
6936

    
6937
/* return true if interface has a gateway */
6938
function interface_has_gateway($friendly) {
6939
	global $config;
6940

    
6941
	if (!empty($config['interfaces'][$friendly])) {
6942
		$ifname = &$config['interfaces'][$friendly];
6943
		switch ($ifname['ipaddr']) {
6944
			case "dhcp":
6945
				/* see https://redmine.pfsense.org/issues/5135 */
6946
				if (get_interface_gateway($friendly)) {
6947
					return true;
6948
				}
6949
				break;
6950
			case "pppoe":
6951
			case "pptp":
6952
			case "l2tp":
6953
			case "ppp":
6954
				return true;
6955
				break;
6956
			default:
6957
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6958
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6959
					return true;
6960
				}
6961
				$tunnelif = substr($ifname['if'], 0, 3);
6962
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6963
					if (find_interface_ip($ifname['if'])) {
6964
						return true;
6965
					}
6966
				}
6967
				if (!empty($ifname['gateway'])) {
6968
					return true;
6969
				}
6970
				break;
6971
		}
6972
	}
6973

    
6974
	return false;
6975
}
6976

    
6977
/* return true if interface has a gateway */
6978
function interface_has_gatewayv6($friendly) {
6979
	global $config;
6980

    
6981
	if (!empty($config['interfaces'][$friendly])) {
6982
		$ifname = &$config['interfaces'][$friendly];
6983
		switch ($ifname['ipaddrv6']) {
6984
			case "slaac":
6985
			case "dhcp6":
6986
			case "6to4":
6987
			case "6rd":
6988
				return true;
6989
				break;
6990
			default:
6991
				if ((substr($ifname['if'], 0, 4) == "ovpn") ||
6992
				    (substr($ifname['if'], 0, 5) == "ipsec")) {
6993
					return true;
6994
				}
6995
				$tunnelif = substr($ifname['if'], 0, 3);
6996
				if ($tunnelif == "gif" || $tunnelif == "gre") {
6997
					if (find_interface_ipv6($ifname['if'])) {
6998
						return true;
6999
					}
7000
				}
7001
				if (!empty($ifname['gatewayv6'])) {
7002
					return true;
7003
				}
7004
				break;
7005
		}
7006
	}
7007

    
7008
	return false;
7009
}
7010

    
7011
/****f* interfaces/is_altq_capable
7012
 * NAME
7013
 *   is_altq_capable - Test if interface is capable of using ALTQ
7014
 * INPUTS
7015
 *   $int            - string containing interface name
7016
 * RESULT
7017
 *   boolean         - true or false
7018
 ******/
7019

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

    
7035
	$int_family = remove_ifindex($int);
7036

    
7037
	if (in_array($int_family, $capable)) {
7038
		return true;
7039
	} elseif (stristr($int, "l2tp")) { /* VLANs are named $parent_$vlan now */
7040
		return true;
7041
	} elseif (interface_is_vlan($int) != NULL) { /* VLANs are named $parent.$vlan now */
7042
		return true;
7043
	} elseif (stristr($int, "_wlan")) { /* WLANs are named $parent_$wlan now */
7044
		return true;
7045
	} else {
7046
		return false;
7047
	}
7048
}
7049

    
7050
/****f* interfaces/is_interface_wireless
7051
 * NAME
7052
 *   is_interface_wireless - Returns if an interface is wireless
7053
 * RESULT
7054
 *   $tmp       - Returns if an interface is wireless
7055
 ******/
7056
function is_interface_wireless($interface) {
7057
	global $config, $g;
7058

    
7059
	$friendly = convert_real_interface_to_friendly_interface_name($interface);
7060
	if (!isset($config['interfaces'][$friendly]['wireless'])) {
7061
		if (preg_match($g['wireless_regex'], $interface)) {
7062
			if (isset($config['interfaces'][$friendly])) {
7063
				$config['interfaces'][$friendly]['wireless'] = array();
7064
			}
7065
			return true;
7066
		}
7067
		return false;
7068
	} else {
7069
		return true;
7070
	}
7071
}
7072

    
7073
function get_wireless_modes($interface) {
7074
	/* return wireless modes and channels */
7075
	$wireless_modes = array();
7076

    
7077
	$cloned_interface = get_real_interface($interface);
7078

    
7079
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7080
		$chan_list = "/sbin/ifconfig {$cloned_interface} list chan";
7081
		$stack_list = "/usr/bin/awk -F\"Channel \" '{ gsub(/\\*/, \" \"); print \$2 \"\\n\" \$3 }'";
7082
		$format_list = "/usr/bin/awk '{print \$5 \" \" \$6 \",\" \$1}'";
7083

    
7084
		$interface_channels = "";
7085
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7086
		$interface_channel_count = count($interface_channels);
7087

    
7088
		$c = 0;
7089
		while ($c < $interface_channel_count) {
7090
			$channel_line = explode(",", $interface_channels["$c"]);
7091
			$wireless_mode = trim($channel_line[0]);
7092
			$wireless_channel = trim($channel_line[1]);
7093
			if (trim($wireless_mode) != "") {
7094
				/* if we only have 11g also set 11b channels */
7095
				if ($wireless_mode == "11g") {
7096
					if (!isset($wireless_modes["11b"])) {
7097
						$wireless_modes["11b"] = array();
7098
					}
7099
				} elseif ($wireless_mode == "11g ht") {
7100
					if (!isset($wireless_modes["11b"])) {
7101
						$wireless_modes["11b"] = array();
7102
					}
7103
					if (!isset($wireless_modes["11g"])) {
7104
						$wireless_modes["11g"] = array();
7105
					}
7106
					$wireless_mode = "11ng";
7107
				} elseif ($wireless_mode == "11a ht") {
7108
					if (!isset($wireless_modes["11a"])) {
7109
						$wireless_modes["11a"] = array();
7110
					}
7111
					$wireless_mode = "11na";
7112
				}
7113
				$wireless_modes["$wireless_mode"]["$c"] = $wireless_channel;
7114
			}
7115
			$c++;
7116
		}
7117
	}
7118
	return($wireless_modes);
7119
}
7120

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

    
7126
		$interface_channels = "";
7127
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7128
		return $interface_channels;
7129
}
7130

    
7131
/* return wireless HT modes */
7132
function get_wireless_ht_modes($interface) {
7133
	$wireless_hts_supported = array(0 => gettext('Auto'));
7134

    
7135
	$cloned_interface = get_real_interface($interface);
7136

    
7137
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7138
		$interface_channels = get_wireless_channels($cloned_interface);
7139

    
7140
		foreach ($interface_channels as $channel) {
7141
			$channel_line = explode(",", $channel);
7142
			$wireless_ht = trim($channel_line[1]);
7143
			if (!empty($wireless_ht)) {
7144
				$wireless_hts_supported[$wireless_ht] = strtoupper($wireless_ht);
7145
			}
7146
		}
7147
	}
7148
	return($wireless_hts_supported);
7149
}
7150

    
7151
/* return wireless HT by channel/standard */
7152
function get_wireless_ht_list($interface) {
7153
	$wireless_hts = array();
7154

    
7155
	$cloned_interface = get_real_interface($interface);
7156

    
7157
	if ($cloned_interface && is_interface_wireless($cloned_interface)) {
7158
		$interface_channels = get_wireless_channels($cloned_interface);
7159
		$interface_channel_count = count($interface_channels);
7160

    
7161
		$c = 0;
7162
		while ($c < $interface_channel_count) {
7163
			$channel_line = explode(",", $interface_channels["$c"]);
7164
			$wireless_mode = trim($channel_line[0]);
7165
			$wireless_ht = trim($channel_line[1]);
7166
			$wireless_channel = trim($channel_line[2]);
7167
			if (!empty($wireless_mode) && !empty($wireless_ht)) {
7168
				if ($wireless_mode == "11g") {
7169
					if (!isset($wireless_modes["11g"])) {
7170
						$wireless_hts["11g"] = array();
7171
					}
7172
					$wireless_mode = "11ng";
7173
				} elseif ($wireless_mode == "11a") {
7174
					if (!isset($wireless_modes["11a"])) {
7175
						$wireless_hts["11a"] = array();
7176
					}
7177
					$wireless_mode = "11na";
7178
				}
7179
				$wireless_hts["$wireless_mode"]["$wireless_channel"][] = $wireless_ht;
7180
			}
7181
			$c++;
7182
		}
7183
	}
7184
	return($wireless_hts);
7185
}
7186

    
7187
/* return channel numbers, frequency, max txpower, and max regulation txpower */
7188
function get_wireless_channel_info($interface) {
7189
	$wireless_channels = array();
7190

    
7191
	$cloned_interface = get_real_interface($interface);
7192

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

    
7198
		$interface_channels = "";
7199
		exec("$chan_list | $stack_list | /usr/bin/sort -u | $format_list 2>&1", $interface_channels);
7200

    
7201
		foreach ($interface_channels as $channel_line) {
7202
			$channel_line = explode(",", $channel_line);
7203
			if (!isset($wireless_channels[$channel_line[0]])) {
7204
				$wireless_channels[$channel_line[0]] = $channel_line;
7205
			}
7206
		}
7207
	}
7208
	return($wireless_channels);
7209
}
7210

    
7211
function set_interface_mtu($interface, $mtu) {
7212

    
7213
	/* LAGG interface must be destroyed and re-created to change MTU */
7214
	if ((substr($interface, 0, 4) == 'lagg') &&
7215
	    (!strstr($interface, "."))) {
7216
		if (isset($config['laggs']['lagg']) &&
7217
		    is_array($config['laggs']['lagg'])) {
7218
			foreach ($config['laggs']['lagg'] as $lagg) {
7219
				if ($lagg['laggif'] == $interface) {
7220
					interface_lagg_configure($lagg);
7221
					break;
7222
				}
7223
			}
7224
		}
7225
	} else {
7226
		pfSense_interface_mtu($interface, $mtu);
7227
		set_ipv6routes_mtu($interface, $mtu);
7228
	}
7229
}
7230

    
7231
/****f* interfaces/get_interface_mtu
7232
 * NAME
7233
 *   get_interface_mtu - Return the mtu of an interface
7234
 * RESULT
7235
 *   $tmp       - Returns the mtu of an interface
7236
 ******/
7237
function get_interface_mtu($interface) {
7238
	$mtu = pfSense_interface_getmtu($interface);
7239
	return $mtu['mtu'];
7240
}
7241

    
7242
function get_interface_mac($interface) {
7243
	$macinfo = pfSense_get_interface_addresses($interface);
7244
	return $macinfo["macaddr"];
7245
}
7246

    
7247
function get_interface_vendor_mac($interface) {
7248
	global $config, $g;
7249

    
7250
	$macinfo = pfSense_get_interface_addresses($interface);
7251
	if (isset($macinfo["hwaddr"]) && $macinfo["hwaddr"] !=
7252
	    "00:00:00:00:00:00") {
7253
		return ($macinfo["hwaddr"]);
7254
	}
7255

    
7256
	$hwaddr_file = "{$g['tmp_path']}/{$interface}_hwaddr";
7257
	if (file_exists($hwaddr_file)) {
7258
		$macaddr = trim(file_get_contents($hwaddr_file));
7259
		if (is_macaddr($macaddr)) {
7260
			return ($macaddr);
7261
		}
7262
	} elseif (is_macaddr($macinfo['macaddr'])) {
7263
		/* Save original macaddress to be restored when necessary */
7264
		@file_put_contents($hwaddr_file, $macinfo['macaddr']);
7265
	}
7266

    
7267
	return (NULL);
7268
}
7269

    
7270
/****f* pfsense-utils/generate_random_mac_address
7271
 * NAME
7272
 *   generate_random_mac - generates a random mac address
7273
 * INPUTS
7274
 *   none
7275
 * RESULT
7276
 *   $mac - a random mac address
7277
 ******/
7278
function generate_random_mac_address() {
7279
	$mac = "02";
7280
	for ($x = 0; $x < 5; $x++) {
7281
		$mac .= ":" . dechex(rand(16, 255));
7282
	}
7283
	return $mac;
7284
}
7285

    
7286
function interface_setup_pppoe_reset_file($pppif, $iface="") {
7287
	global $g;
7288

    
7289
	$cron_file = "{$g['varetc_path']}/pppoe_restart_{$pppif}";
7290

    
7291
	if (!empty($iface) && !empty($pppif)) {
7292
		$cron_cmd = <<<EOD
7293
#!/bin/sh
7294
/usr/local/sbin/pfSctl -c 'interface reload {$iface}'
7295
/usr/bin/logger -t {$pppif} "PPPoE periodic reset executed on {$iface}"
7296

    
7297
EOD;
7298

    
7299
		@file_put_contents($cron_file, $cron_cmd);
7300
		chmod($cron_file, 0755);
7301
		sigkillbypid("{$g['varrun_path']}/cron.pid", "HUP");
7302
	} else {
7303
		unlink_if_exists($cron_file);
7304
	}
7305
}
7306

    
7307
function get_interface_default_mtu($type = "ethernet") {
7308
	switch ($type) {
7309
		case "gre":
7310
			return 1476;
7311
			break;
7312
		case "gif":
7313
			return 1280;
7314
			break;
7315
		case "tun":
7316
		case "vlan":
7317
		case "tap":
7318
		case "ethernet":
7319
		default:
7320
			return 1500;
7321
			break;
7322
	}
7323

    
7324
	/* Never reached */
7325
	return 1500;
7326
}
7327

    
7328
function get_vip_descr($ipaddress) {
7329
	global $config;
7330

    
7331
	foreach ($config['virtualip']['vip'] as $vip) {
7332
		if ($vip['subnet'] == $ipaddress) {
7333
			return ($vip['descr']);
7334
		}
7335
	}
7336
	return "";
7337
}
7338

    
7339
function interfaces_staticarp_configure($if) {
7340
	global $config, $g;
7341
	if (isset($config['system']['developerspew'])) {
7342
		$mt = microtime();
7343
		echo "interfaces_staticarp_configure($if) being called $mt\n";
7344
	}
7345

    
7346
	$ifcfg = $config['interfaces'][$if];
7347

    
7348
	if (empty($if) || empty($ifcfg['if']) || !isset($ifcfg['enable'])) {
7349
		return 0;
7350
	}
7351

    
7352
	/* Enable staticarp, if enabled */
7353
	if (isset($config['dhcpd'][$if]['staticarp'])) {
7354
		mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " staticarp ");
7355
		mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7356
	} else {
7357
		/*
7358
		 * Interfaces do not have staticarp enabled by default
7359
		 * Let's not disable staticarp on freshly created interfaces
7360
		 */
7361
		if (!platform_booting()) {
7362
			mwexec("/sbin/ifconfig " . escapeshellarg($ifcfg['if']) . " -staticarp ");
7363
			mwexec("/usr/sbin/arp -d -i " . escapeshellarg($ifcfg['if']) . " -a > /dev/null 2>&1 ");
7364
		}
7365
	}
7366

    
7367
	/* Enable static arp entries */
7368
	if (is_array($config['dhcpd'][$if]) && is_array($config['dhcpd'][$if]['staticmap'])) {
7369
		foreach ($config['dhcpd'][$if]['staticmap'] as $arpent) {
7370
			if (empty($arpent['ipaddr']) || empty($arpent['mac'])) {
7371
				continue;
7372
			}
7373
			if (isset($config['dhcpd'][$if]['staticarp']) || isset($arpent['arp_table_static_entry'])) {
7374
				mwexec("/usr/sbin/arp -s " . escapeshellarg($arpent['ipaddr']) . " " . escapeshellarg($arpent['mac']));
7375
			}
7376
		}
7377
	}
7378

    
7379
	return 0;
7380
}
7381

    
7382
function get_failover_interface($interface, $family = "all", $gateways_status = false) {
7383
	global $config;
7384

    
7385
	/* shortcut to get_real_interface if we find it in the config */
7386
	if (is_array($config['interfaces'][$interface])) {
7387
		return get_real_interface($interface, $family);
7388
	}
7389

    
7390
	/* compare against gateway groups */
7391
	$a_groups = return_gateway_groups_array(true, $gateways_status);
7392
	if (is_array($a_groups[$interface])) {
7393
		/* we found a gateway group, fetch the interface or vip */
7394
		if (!empty($a_groups[$interface][0]['vip'])) {
7395
			return $a_groups[$interface][0]['vip'];
7396
		} else {
7397
			return $a_groups[$interface][0]['int'];
7398
		}
7399
	}
7400
	/* fall through to get_real_interface */
7401
	/* XXX: Really needed? */
7402
	return get_real_interface($interface, $family);
7403
}
7404

    
7405
/****f* interfaces/interface_has_dhcp
7406
 * NAME
7407
 *   interface_has_dhcp - determine if the interface or gateway group uses DHCP
7408
 * INPUTS
7409
 *   interface or gateway group name
7410
 *   family - 4 (check for IPv4 DHCP) or 6 (check for IPv6 DHCP)
7411
 * RESULT
7412
 *   true - if the interface uses DHCP/DHCP6, or the name is a gateway group which has any member that uses DHCP/DHCP6
7413
 *   false - otherwise (DHCP/DHCP6 not in use, or the name is not an interface or gateway group)
7414
 ******/
7415
function interface_has_dhcp($interface, $family = 4) {
7416
	global $config;
7417

    
7418
	if ($config['interfaces'][$interface]) {
7419
		if (($family == 4) && ($config['interfaces'][$interface]['ipaddr'] == "dhcp")) {
7420
			return true;
7421
		} elseif (($family == 6) && ($config['interfaces'][$interface]['ipaddrv6'] == "dhcp6")) {
7422
			return true;
7423
		} else {
7424
			return false;
7425
		}
7426
	}
7427

    
7428
	if (!is_array($config['gateways']['gateway_group'])) {
7429
		return false;
7430
	}
7431

    
7432
	if ($family == 6) {
7433
		$dhcp_string = "_DHCP6";
7434
	} else {
7435
		$dhcp_string = "_DHCP";
7436
	}
7437

    
7438
	foreach ($config['gateways']['gateway_group'] as $group) {
7439
		if (($group['name'] != $interface) || !is_array($group['item'])) {
7440
			continue;
7441
		}
7442
		foreach ($group['item'] as $item) {
7443
			$item_data = explode("|", $item);
7444
			if (substr($item_data[0], -strlen($dhcp_string)) == $dhcp_string) {
7445
				return true;
7446
			}
7447
		}
7448
	}
7449

    
7450
	return false;
7451
}
7452

    
7453
function remove_ifindex($ifname) {
7454
	return preg_replace("/[0-9]+$/", "", $ifname);
7455
}
7456

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

    
7460
	$viplist = get_configured_vip_list($family, $type);
7461
	foreach ($viplist as $vip => $address) {
7462
		$interfaces[$vip] = $address;
7463
		if ($type = VIP_CARP) {
7464
			$vip = get_configured_vip($vipid);
7465
			if (isset($vip) && is_array($vip) ) {
7466
				$interfaces[$vipid] .= " - vhid {$vip['vhid']}";
7467
			}
7468
		}
7469
		if (get_vip_descr($address)) {
7470
			$interfaces[$vip] .= " (" . get_vip_descr($address) . ")";
7471
		}
7472
	}
7473
	return $interfaces;
7474
}
7475

    
7476
function return_gateway_groups_array_with_descr() {
7477
	$interfaces = array();
7478
	$grouplist = return_gateway_groups_array();
7479
	foreach ($grouplist as $name => $group) {
7480
		if ($group[0]['vip'] != "") {
7481
			$vipif = $group[0]['vip'];
7482
		} else {
7483
			$vipif = $group[0]['int'];
7484
		}
7485

    
7486
		$interfaces[$name] = "GW Group {$name}";
7487
	}
7488
	return $interfaces;
7489
}
7490

    
7491
function get_serial_ports($short=false) {
7492
	$linklist = array();
7493
	if (!is_dir("/var/spool/lock")) {
7494
		mwexec("/bin/mkdir -p /var/spool/lock");
7495
	}
7496
	$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);
7497
	foreach ($serialports as $port) {
7498
		$port = trim($port);
7499
		$port = ($short) ? basename($port) : $port;
7500
		$linklist[$port] = $port;
7501
	}
7502
	return $linklist;
7503
}
7504

    
7505
function get_interface_ports() {
7506
	global $config;
7507
	$linklist = array();
7508
	$portlist = get_interface_list();
7509
	if (is_array($config['vlans']['vlan']) && count($config['vlans']['vlan'])) {
7510
		foreach ($config['vlans']['vlan'] as $vlan) {
7511
			$portlist[$vlan['vlanif']] = $vlan;
7512
		}
7513
	}
7514

    
7515
	if (is_array($config['qinqs']['qinqentry']) && count($config['qinqs']['qinqentry'])) {
7516
		foreach ($config['qinqs']['qinqentry'] as $qinq) {
7517
			$members = explode(" ", $qinq['members']);
7518
			foreach ($members as $mem) {
7519
				$qentry = $qinq['vlanif'] . "." . $mem;
7520
				$portlist[$qentry] = $qentry;
7521
			}
7522
		}
7523
	}
7524

    
7525
	foreach ($portlist as $ifn => $ifinfo) {
7526
		$string = "";
7527
		if (is_array($ifinfo)) {
7528
			$string .= $ifn;
7529
			if ($ifinfo['mac']) {
7530
				$string .= " ({$ifinfo['mac']})";
7531
			}
7532
			if ($ifinfo['friendly']) {
7533
				$string .= " - " . convert_friendly_interface_to_friendly_descr($ifinfo['friendly']);
7534
			} elseif ($ifinfo['descr']) {
7535
				$string .= " - {$ifinfo['descr']}";
7536
			}
7537
		} else {
7538
			$string .= $ifinfo;
7539
		}
7540

    
7541
		$linklist[$ifn] = $string;
7542
	}
7543
	return $linklist;
7544
}
7545

    
7546
function build_ppps_link_list() {
7547
	global $pconfig;
7548

    
7549
	$linklist = array('list' => array(), 'selected' => array());
7550

    
7551
	if ($pconfig['type'] == 'ppp') {
7552
		$linklist['list'] = get_serial_ports();
7553
	} else {
7554
		$iflist = get_interface_ports();
7555

    
7556
		$viplist = array();
7557
		$carplist = get_configured_vip_list_with_descr('all', VIP_CARP);
7558
		foreach ($carplist as $vid => $vaddr) {
7559
			$vip = get_configured_vip($vid);
7560
			$viplist[$vid] = "{$vaddr} (vhid: {$vip['vhid']})";
7561
		}
7562

    
7563
		$linklist['list'] = array_merge($iflist, $viplist);
7564

    
7565
		// The members of a LAGG cannot be assigned, used in VLANs, QinQ, or PPP.
7566
		$lagglist = get_lagg_interface_list();
7567
		foreach ($lagglist as $laggif => $lagg) {
7568
			/* LAGG members cannot be assigned */
7569
			$laggmembers = explode(',', $lagg['members']);
7570
			foreach ($laggmembers as $lagm) {
7571
				if (isset($linklist['list'][$lagm])) {
7572
					unset($linklist['list'][$lagm]);
7573
				}
7574
			}
7575
		}
7576
	}
7577

    
7578
	$selected_ports = array();
7579
	if (is_array($pconfig['interfaces'])) {
7580
		$selected_ports = $pconfig['interfaces'];
7581
	} elseif (!empty($pconfig['interfaces'])) {
7582
		$selected_ports = explode(',', $pconfig['interfaces']);
7583
	}
7584
	foreach ($selected_ports as $port) {
7585
		if (isset($linklist['list'][$port])) {
7586
			array_push($linklist['selected'], $port);
7587
		}
7588
	}
7589
	return($linklist);
7590
}
7591

    
7592
function create_interface_list($open = false) {
7593
	global $config;
7594

    
7595
	$iflist = array();
7596

    
7597
	// add group interfaces
7598
	if (isset($config['ifgroups']['ifgroupentry']) && is_array($config['ifgroups']['ifgroupentry'])) {
7599
		foreach ($config['ifgroups']['ifgroupentry'] as $ifgen) {
7600
			if ($open || have_ruleint_access($ifgen['ifname'])) {
7601
				$iflist[$ifgen['ifname']] = $ifgen['ifname'];
7602
			}
7603
		}
7604
	}
7605

    
7606
	foreach (get_configured_interface_with_descr() as $ifent => $ifdesc) {
7607
		if ($open || have_ruleint_access($ifent)) {
7608
			$iflist[$ifent] = $ifdesc;
7609
		}
7610
	}
7611

    
7612
	if ($config['l2tp']['mode'] == "server" && ($open || have_ruleint_access("l2tp"))) {
7613
		$iflist['l2tp'] = gettext('L2TP VPN');
7614
	}
7615

    
7616
	if (is_pppoe_server_enabled() && ($open || have_ruleint_access("pppoe"))) {
7617
		$iflist['pppoe'] = gettext("PPPoE Server");
7618
	}
7619

    
7620
	// add ipsec interfaces
7621
	if (ipsec_enabled() && ($open || have_ruleint_access("enc0"))) {
7622
		$iflist["enc0"] = gettext("IPsec");
7623
	}
7624

    
7625
	// add openvpn/tun interfaces
7626
	if ($config['openvpn']["openvpn-server"] || $config['openvpn']["openvpn-client"]) {
7627
		$iflist["openvpn"] = gettext("OpenVPN");
7628
	}
7629

    
7630
	return($iflist);
7631
}
7632

    
7633
function is_pseudo_interface($inf, $tap=true) {
7634
	global $config;
7635
	$psifs = array('ovpn', 'ipsec', 'l2tp', 'pptp', 'gif', 'gre', 'ppp', 'pppoe');
7636
	foreach ($psifs as $pif) {
7637
		if (substr($inf, 0, strlen($pif)) == $pif) {
7638
			if (($pif == 'ovpn') && $tap) {
7639
				preg_match('/ovpn([cs])([1-9]+)/', $inf, $m);
7640
				$type = ($m[1] == 'c') ? 'client' : 'server';
7641
				foreach ($config['openvpn']['openvpn-'.$type] as $ovpn) {
7642
					if (($ovpn['vpnid'] == $m[2]) && ($ovpn['dev_mode'] == 'tap')) {
7643
						return false;
7644
					} elseif ($ovpn['vpnid'] == $m[2]) {
7645
						return true;
7646
					}
7647
				}
7648
			} else {
7649
				return true;
7650
			}
7651
		}
7652
	}
7653
	return false;
7654
}
7655

    
7656
function is_stf_interface($inf) {
7657
	global $config;
7658

    
7659
	if (is_array($config['interfaces'][$inf]) &&
7660
	    (($config['interfaces'][$inf]['ipaddrv6'] == '6rd') ||
7661
	    ($config['interfaces'][$inf]['ipaddrv6'] == '6to4'))) {
7662
	    return true;
7663
	}
7664

    
7665
	return false;
7666
}
7667

    
7668
?>
(22-22/61)