Project

General

Profile

Download (39 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	gwlb.inc
4

    
5
	part of pfSense (https://www.pfsense.org)
6
	Copyright (C) 2008 Bill Marquette, Seth Mos
7
	Copyright (c) 2008-2016 Electric Sheep Fencing, LLC. All rights reserved.
8

    
9
	Redistribution and use in source and binary forms, with or without
10
	modification, are permitted provided that the following conditions are met:
11

    
12
	1. Redistributions of source code must retain the above copyright notice,
13
	   this list of conditions and the following disclaimer.
14

    
15
	2. Redistributions in binary form must reproduce the above copyright
16
	   notice, this list of conditions and the following disclaimer in
17
	   the documentation and/or other materials provided with the
18
	   distribution.
19

    
20
	3. All advertising materials mentioning features or use of this software
21
	   must display the following acknowledgment:
22
	   "This product includes software developed by the pfSense Project
23
	   for use in the pfSense® software distribution. (http://www.pfsense.org/).
24

    
25
	4. The names "pfSense" and "pfSense Project" must not be used to
26
	   endorse or promote products derived from this software without
27
	   prior written permission. For written permission, please contact
28
	   coreteam@pfsense.org.
29

    
30
	5. Products derived from this software may not be called "pfSense"
31
	   nor may "pfSense" appear in their names without prior written
32
	   permission of the Electric Sheep Fencing, LLC.
33

    
34
	6. Redistributions of any form whatsoever must retain the following
35
	   acknowledgment:
36

    
37
	"This product includes software developed by the pfSense Project
38
	for use in the pfSense software distribution (http://www.pfsense.org/).
39

    
40
	THIS SOFTWARE IS PROVIDED BY THE pfSense PROJECT ``AS IS'' AND ANY
41
	EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42
	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
43
	PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE pfSense PROJECT OR
44
	ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
45
	SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
46
	NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47
	LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
	HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
49
	STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
50
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
51
	OF THE POSSIBILITY OF SUCH DAMAGE.
52
 */
53

    
54
require_once("config.inc");
55
require_once("rrd.inc");
56

    
57
/* Returns an array of default values used for dpinger */
58
function return_dpinger_defaults() {
59
	return array(
60
		"latencylow" => "200",
61
		"latencyhigh" => "500",
62
		"losslow" => "10",
63
		"losshigh" => "20",
64
		"interval" => "500",
65
		"loss_interval" => "2000",
66
		"time_period" => "60000",
67
		"alert_interval" => "1000",
68
		"data_payload" => "0");
69
}
70

    
71
function running_dpinger_processes() {
72
	global $g;
73

    
74
	$pidfiles = glob("{$g['varrun_path']}/dpinger_*.pid");
75

    
76
	$result = array();
77
	if ($pidfiles === FALSE) {
78
		return $result;
79
	}
80

    
81
	foreach ($pidfiles as $pidfile) {
82
		if (preg_match('/^dpinger_(.+)~([^~]+)~([^~]+)\.pid$/',
83
		    basename($pidfile), $matches)) {
84
			$socket_file = preg_replace('/\.pid$/', '.sock',
85
			    $pidfile);
86
			$result[$matches[1]] = array(
87
			    'srcip'    => $matches[2],
88
			    'targetip' => $matches[3],
89
			    'pidfile'  => $pidfile,
90
			    'socket'   => $socket_file
91
			);
92
			unset($gwinfo);
93
		}
94
	}
95

    
96
	return $result;
97
}
98

    
99
/*
100
 * Stop one or more dpinger process
101
 * default parameter $gwname is '*' that will kill all running sessions
102
 * If a gateway name is passed, only this one will be killed
103
 */
104
function stop_dpinger($gwname = '') {
105
	global $g;
106

    
107
	$running_processes = running_dpinger_processes();
108

    
109
	foreach ($running_processes as $running_gwname => $process) {
110
		if ($gwname != '' && $running_gwname != $gwname) {
111
			continue;
112
		}
113

    
114
		if (isvalidpid($process['pidfile'])) {
115
			killbypid($process['pidfile']);
116
		} else {
117
			@unlink($process['pidfile']);
118
		}
119
	}
120
}
121

    
122
function start_dpinger($gateway) {
123
	global $g;
124

    
125
	if (!isset($gateway['gwifip'])) {
126
		return;
127
	}
128

    
129
	$dpinger_defaults = return_dpinger_defaults();
130

    
131
	$prefix = "{$g['varrun_path']}/dpinger_{$gateway['name']}~" .
132
	    "{$gateway['gwifip']}~{$gateway['monitor']}";
133
	# dpinger socket path should not be longer then uaddr.sun_path
134
	if (strlen($pidfile) > 95) {
135
		$prefix = "{$g['varrun_path']}/dpinger_{$gateway['name']}~" .
136
		    substr(md5($gateway['gwifip']),0,8) . "~" .
137
		    $gateway['monitor'];
138
	}
139
	$pidfile = $prefix . ".pid";
140
	$socket = $prefix . ".sock";
141
	$alarm_cmd = "{$g['etc_path']}/rc.gateway_alarm";
142

    
143
	$params  = "-S ";			/* Log warnings via syslog */
144
	$params .= "-r 0 ";			/* Disable unused reporting thread */
145
	$params .= "-i {$gateway['name']} ";	/* Identifier */
146
	$params .= "-B {$gateway['gwifip']} ";	/* Bind src address */
147
	$params .= "-p {$pidfile} ";		/* PID filename */
148
	$params .= "-u {$socket} ";		/* Status Socket */
149
	$params .= "-C \"{$alarm_cmd}\" ";	/* Command to run on alarm */
150

    
151
	$params .= "-d " .
152
	    (isset($gateway['data_payload']) && is_numeric($gateway['data_payload'])
153
	    ? $gateway['data_payload']
154
	    : $dpinger_defaults['data_payload']
155
	    ) . " ";
156

    
157
	$params .= "-s " .
158
	    (isset($gateway['interval']) && is_numeric($gateway['interval'])
159
	    ? $gateway['interval']
160
	    : $dpinger_defaults['interval']
161
	    ) . " ";
162

    
163
	$params .= "-l " .
164
	    (isset($gateway['loss_interval']) && is_numeric($gateway['loss_interval'])
165
	    ?  $gateway['loss_interval']
166
	    : $dpinger_defaults['loss_interval']
167
	    ) . " ";
168

    
169
	$params .= "-t " .
170
	    (isset($gateway['time_period']) && is_numeric($gateway['time_period'])
171
	    ?  $gateway['time_period']
172
	    : $dpinger_defaults['time_period']
173
	    ) . " ";
174

    
175
	$params .= "-A " .
176
	    (isset($gateway['alert_interval']) && is_numeric($gateway['alert_interval'])
177
	    ?  $gateway['alert_interval']
178
	    : $dpinger_defaults['alert_interval']
179
	    ) . " ";
180

    
181
	$params .= "-D " .
182
	    (isset($gateway['latencyhigh']) && is_numeric($gateway['latencyhigh'])
183
	    ?  $gateway['latencyhigh']
184
	    : $dpinger_defaults['latencyhigh']
185
	    ) . " ";
186

    
187
	$params .= "-L " .
188
	    (isset($gateway['losshigh']) && is_numeric($gateway['losshigh'])
189
	    ?  $gateway['losshigh']
190
	    : $dpinger_defaults['losshigh']
191
	    ) . " ";
192

    
193
	/* Make sure we don't end up with 2 process for the same GW */
194
	stop_dpinger($gateway['name']);
195

    
196
	/* Redirect stdout to /dev/null to avoid exec() to wait for dpinger */
197
	return mwexec("/usr/local/bin/dpinger {$params} {$gateway['monitor']} >/dev/null");
198
}
199

    
200
/*
201
 * Starts dpinger processes and adds appropriate static routes for monitor IPs
202
 */
203
function setup_gateways_monitor() {
204
	global $config, $g;
205

    
206
	$gateways_arr = return_gateways_array();
207
	if (!is_array($gateways_arr)) {
208
		log_error(gettext("No gateways to monitor. dpinger will not run."));
209
		stop_dpinger();
210
		return;
211
	}
212

    
213
	$monitor_ips = array();
214
	foreach ($gateways_arr as $gwname => $gateway) {
215
		/* Do not monitor if such was requested */
216
		if (isset($gateway['monitor_disable'])) {
217
			continue;
218
		}
219
		if (empty($gateway['monitor']) || !is_ipaddr($gateway['monitor'])) {
220
			if (is_ipaddr($gateway['gateway'])) {
221
				$gateways_arr[$gwname]['monitor'] = $gateway['gateway'];
222
			} else { /* No chance to get an ip to monitor skip target. */
223
				continue;
224
			}
225
		}
226

    
227
		/* if the monitor address is already used before, skip */
228
		if (in_array($gateway['monitor'], $monitor_ips)) {
229
			continue;
230
		}
231

    
232
		/* Interface ip is needed since dpinger will bind a socket to it.
233
		 * However the config GUI should already have checked this and when
234
		 * PPPoE is used the IP address is set to "dynamic". So using is_ipaddrv4
235
		 * or is_ipaddrv6 to identify packet type would be wrong, especially as
236
		 * further checks (that can cope with the "dynamic" case) are present inside
237
		 * the if block. So using $gateway['ipprotocol'] is the better option.
238
		 */
239
		if ($gateway['ipprotocol'] == "inet") { // This is an IPv4 gateway...
240
			$gwifip = find_interface_ip($gateway['interface'], true);
241
			if (!is_ipaddrv4($gwifip)) {
242
				continue; //Skip this target
243
			}
244

    
245
			if ($gwifip == "0.0.0.0") {
246
				continue; //Skip this target - the gateway is still waiting for DHCP
247
			}
248

    
249
			/*
250
			 * If the gateway is the same as the monitor we do not add a
251
			 * route as this will break the routing table.
252
			 * Add static routes for each gateway with their monitor IP
253
			 * not strictly necessary but is a added level of protection.
254
			 */
255
			if (is_ipaddrv4($gateway['gateway']) && $gateway['monitor'] != $gateway['gateway']) {
256
				log_error(sprintf(gettext('Removing static route for monitor %1$s and adding a new route through %2$s'), $gateway['monitor'], $gateway['gateway']));
257
				if (interface_isppp_type($gateway['friendlyiface'])) {
258
					mwexec("/sbin/route change -host " . escapeshellarg($gateway['monitor']) .
259
						" -iface " . escapeshellarg($gateway['interface']), true);
260
				} else {
261
					mwexec("/sbin/route change -host " . escapeshellarg($gateway['monitor']) .
262
						" " . escapeshellarg($gateway['gateway']), true);
263
				}
264

    
265
				pfSense_kill_states("0.0.0.0/0", $gateway['monitor'], $gateway['interface'], "icmp");
266
			}
267
		} else if ($gateway['ipprotocol'] == "inet6") { // This is an IPv6 gateway...
268
			if (is_linklocal($gateway['gateway']) &&
269
			    get_ll_scope($gateway['gateway']) == '') {
270
				$gateway['gateway'] .= '%' . $gateway['interface'];
271
			}
272

    
273
			if (is_linklocal($gateway['monitor'])) {
274
				if (get_ll_scope($gateway['monitor']) == '') {
275
					$gateways_arr[$gwname]['monitor'] .= '%' . $gateway['interface'];
276
				}
277

    
278
				$gwifip = find_interface_ipv6_ll($gateway['interface'], true);
279

    
280
				if (get_ll_scope($gwifip) == '') {
281
					$gwifip .= '%' . $gateway['interface'];
282
				}
283
			} else {
284
				$gwifip = find_interface_ipv6($gateway['interface'], true);
285
			}
286

    
287
			if (!is_ipaddrv6($gwifip)) {
288
				continue; //Skip this target
289
			}
290

    
291
			/*
292
			 * If the gateway is the same as the monitor we do not add a
293
			 * route as this will break the routing table.
294
			 * Add static routes for each gateway with their monitor IP
295
			 * not strictly necessary but is a added level of protection.
296
			 */
297
			if ($gateway['gateway'] != $gateway['monitor']) {
298
				log_error(sprintf(gettext('Removing static route for monitor %1$s and adding a new route through %2$s'), $gateway['monitor'], $gateway['gateway']));
299
				if (interface_isppp_type($gateway['friendlyiface'])) {
300
					mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gateway['monitor']) .
301
						" -iface " . escapeshellarg($gateway['interface']), true);
302
				} else {
303
					mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gateway['monitor']) .
304
						" " . escapeshellarg($gateway['gateway']), true);
305
				}
306

    
307
				pfSense_kill_states("::0.0.0.0/0", $gateway['monitor'], $gateway['interface'], "icmpv6");
308
			}
309
		} else {
310
			continue;
311
		}
312

    
313
		$monitor_ips[] = $gateway['monitor'];
314
		$gateways_arr[$gwname]['enable_dpinger'] = true;
315
		$gateways_arr[$gwname]['gwifip'] = $gwifip;
316
	}
317

    
318
	stop_dpinger();
319

    
320
	/* Start new processes */
321
	foreach ($gateways_arr as $gateway) {
322
		if (!isset($gateway['enable_dpinger'])) {
323
			continue;
324
		}
325

    
326
		if (start_dpinger($gateway) != 0) {
327
			log_error(sprintf(gettext("Error starting gateway monitor for %s"), $gateway['name']));
328
		}
329
	}
330

    
331
	return;
332
}
333

    
334
function get_dpinger_status($gwname) {
335
	global $g;
336

    
337
	$running_processes = running_dpinger_processes();
338

    
339
	if (!isset($running_processes[$gwname])) {
340
		log_error(sprintf(gettext('dpinger: No dpinger session running for gateway %s'), $gwname));
341
		return false;
342
	}
343

    
344
	$proc = $running_processes[$gwname];
345
	unset($running_processes);
346

    
347
	if (!file_exists($proc['socket'])) {
348
		log_error("dpinger: status socket {$proc['socket']} not found");
349
		return false;
350
	}
351

    
352
	$fp = stream_socket_client("unix://{$proc['socket']}", $errno, $errstr, 10);
353
	if (!$fp) {
354
		log_error(sprintf(gettext('dpinger: cannot connect to status socket %1$s - %2$s (%3$s)'), $proc['socket'], $errstr, $errno));
355
		return false;
356
	}
357

    
358
	$status = '';
359
	while (!feof($fp)) {
360
		$status .= fgets($fp, 1024);
361
	}
362
	fclose($fp);
363

    
364
	$r = array();
365
	list(
366
	    $r['gwname'],
367
	    $r['latency_avg'],
368
	    $r['latency_stddev'],
369
	    $r['loss']
370
	) = explode(' ', preg_replace('/\n/', '', $status));
371

    
372
	$r['srcip'] = $proc['srcip'];
373
	$r['targetip'] = $proc['targetip'];
374

    
375
	$gateways_arr = return_gateways_array();
376
	unset($gw);
377
	if (isset($gateways_arr[$gwname])) {
378
		$gw = $gateways_arr[$gwname];
379
	}
380

    
381
	$r['latency_avg'] = round($r['latency_avg']/1000, 3);
382
	$r['latency_stddev'] = round($r['latency_stddev']/1000, 3);
383

    
384
	$r['status'] = "none";
385
	if (isset($gw) && isset($gw['force_down'])) {
386
		$r['status'] = "force_down";
387
	} else if (isset($gw)) {
388
		$settings = return_dpinger_defaults();
389

    
390
		$keys = array(
391
		    'latencylow',
392
		    'latencyhigh',
393
		    'losslow',
394
		    'losshigh'
395
		);
396

    
397
		/* Replace default values by user-defined */
398
		foreach ($keys as $key) {
399
			if (isset($gw[$key]) && is_numeric($gw[$key])) {
400
				$settings[$key] = $gw[$key];
401
			}
402
		}
403

    
404
		if ($r['latency_avg'] > $settings['latencyhigh'] ||
405
		    $r['loss'] > $settings['losshigh']) {
406
			$r['status'] = "down";
407
		} else if ($r['latency_avg'] > $settings['latencylow']) {
408
			$r['status'] = "delay";
409
		} else if ($r['loss'] > $settings['losslow']) {
410
			$r['status'] = "loss";
411
		}
412
	}
413

    
414
	return $r;
415
}
416

    
417
/* return the status of the dpinger targets as an array */
418
function return_gateways_status($byname = false) {
419
	global $config, $g;
420

    
421
	$dpinger_gws = running_dpinger_processes();
422
	$status = array();
423

    
424
	$gateways_arr = return_gateways_array();
425

    
426
	foreach ($dpinger_gws as $gwname => $gwdata) {
427
		$dpinger_status = get_dpinger_status($gwname);
428
		if ($dpinger_status === false) {
429
			continue;
430
		}
431

    
432
		if ($byname == false) {
433
			$target = $dpinger_status['targetip'];
434
		} else {
435
			$target = $gwname;
436
		}
437

    
438
		$status[$target] = array();
439
		$status[$target]['monitorip'] = $dpinger_status['targetip'];
440
		$status[$target]['srcip'] = $dpinger_status['srcip'];
441
		$status[$target]['name'] = $gwname;
442
		$status[$target]['delay'] = empty($dpinger_status['latency_avg']) ? "0ms" : $dpinger_status['latency_avg'] . "ms";
443
		$status[$target]['stddev'] = empty($dpinger_status['latency_stddev']) ? "0ms" : $dpinger_status['latency_stddev'] . "ms";
444
		$status[$target]['loss'] = empty($dpinger_status['loss']) ? "0.0%" : round($dpinger_status['loss'], 1) . "%";
445
		$status[$target]['status'] = $dpinger_status['status'];
446
	}
447

    
448
	/* tack on any gateways that have monitoring disabled
449
	 * or are down, which could cause gateway groups to fail */
450
	$gateways_arr = return_gateways_array();
451
	foreach ($gateways_arr as $gwitem) {
452
		if (!isset($gwitem['monitor_disable'])) {
453
			continue;
454
		}
455
		if (!is_ipaddr($gwitem['monitor'])) {
456
			$realif = $gwitem['interface'];
457
			$tgtip = get_interface_gateway($realif);
458
			if (!is_ipaddr($tgtip)) {
459
				$tgtip = "none";
460
			}
461
			$srcip = find_interface_ip($realif);
462
		} else {
463
			$tgtip = $gwitem['monitor'];
464
			$srcip = find_interface_ip($realif);
465
		}
466
		if ($byname == true) {
467
			$target = $gwitem['name'];
468
		} else {
469
			$target = $tgtip;
470
		}
471

    
472
		/* failsafe for down interfaces */
473
		if ($target == "none") {
474
			$target = $gwitem['name'];
475
			$status[$target]['name'] = $gwitem['name'];
476
			$status[$target]['delay'] = "0.0ms";
477
			$status[$target]['loss'] = "100.0%";
478
			$status[$target]['status'] = "down";
479
		} else {
480
			$status[$target]['monitorip'] = $tgtip;
481
			$status[$target]['srcip'] = $srcip;
482
			$status[$target]['name'] = $gwitem['name'];
483
			$status[$target]['delay'] = "";
484
			$status[$target]['loss'] = "";
485
			$status[$target]['status'] = "none";
486
		}
487
	}
488
	return($status);
489
}
490

    
491
/* Return all configured gateways on the system */
492
function return_gateways_array($disabled = false, $localhost = false, $inactive = false) {
493
	global $config, $g;
494

    
495
	$gateways_arr = array();
496
	$gateways_arr_temp = array();
497

    
498
	$found_defaultv4 = 0;
499
	$found_defaultv6 = 0;
500

    
501
	// Ensure the interface cache is up to date first
502
	$interfaces = get_interface_arr(true);
503

    
504
	$i = -1;
505
	/* Process/add all the configured gateways. */
506
	if (is_array($config['gateways']['gateway_item'])) {
507
		foreach ($config['gateways']['gateway_item'] as $gateway) {
508
			/* Increment it here to do not skip items */
509
			$i++;
510

    
511
			if (empty($config['interfaces'][$gateway['interface']])) {
512
				if ($inactive === false) {
513
					continue;
514
				} else {
515
					$gateway['inactive'] = true;
516
				}
517
			}
518
			$wancfg = $config['interfaces'][$gateway['interface']];
519

    
520
			/* skip disabled interfaces */
521
			if ($disabled === false && (!isset($wancfg['enable']))) {
522
				continue;
523
			}
524

    
525
			/* if the gateway is dynamic and we can find the IPv4, Great! */
526
			if (empty($gateway['gateway']) || $gateway['gateway'] == "dynamic") {
527
				if ($gateway['ipprotocol'] == "inet") {
528
					/* we know which interfaces is dynamic, this should be made a function */
529
					$gateway['gateway'] = get_interface_gateway($gateway['interface']);
530
					/* no IP address found, set to dynamic */
531
					if (!is_ipaddrv4($gateway['gateway'])) {
532
						$gateway['gateway'] = "dynamic";
533
					}
534
					$gateway['dynamic'] = true;
535
				}
536

    
537
				/* if the gateway is dynamic and we can find the IPv6, Great! */
538
				else if ($gateway['ipprotocol'] == "inet6") {
539
					/* we know which interfaces is dynamic, this should be made a function, and for v6 too */
540
					$gateway['gateway'] = get_interface_gateway_v6($gateway['interface']);
541
					/* no IPv6 address found, set to dynamic */
542
					if (!is_ipaddrv6($gateway['gateway'])) {
543
						$gateway['gateway'] = "dynamic";
544
					}
545
					$gateway['dynamic'] = true;
546
				}
547
			} else {
548
				/* getting this detection right is hard at this point because we still don't
549
				 * store the address family in the gateway item */
550
				if (is_ipaddrv4($gateway['gateway'])) {
551
					$gateway['ipprotocol'] = "inet";
552
				} else if (is_ipaddrv6($gateway['gateway'])) {
553
					$gateway['ipprotocol'] = "inet6";
554
				}
555
			}
556

    
557
			if (isset($gateway['monitor_disable'])) {
558
				$gateway['monitor_disable'] = true;
559
			} else if (empty($gateway['monitor'])) {
560
				$gateway['monitor'] = $gateway['gateway'];
561
			}
562

    
563
			$gateway['friendlyiface'] = $gateway['interface'];
564

    
565
			/* special treatment for tunnel interfaces */
566
			if ($gateway['ipprotocol'] == "inet6") {
567
				$gateway['interface'] = get_real_interface($gateway['interface'], "inet6", false, false);
568
			} else {
569
				$gateway['interface'] = get_real_interface($gateway['interface'], "inet", false, false);
570
			}
571

    
572
			/* entry has a default flag, use it */
573
			if (isset($gateway['defaultgw'])) {
574
				if ($gateway['ipprotocol'] == "inet") {
575
					$gateway['defaultgw'] = true;
576
					$found_defaultv4 = 1;
577
				} else if ($gateway['ipprotocol'] == "inet6") {
578
					$gateway['defaultgw'] = true;
579
					$found_defaultv6 = 1;
580
				}
581
			}
582
			/* include the gateway index as the attribute */
583
			$gateway['attribute'] = $i;
584

    
585
			/* Remember all the gateway names, even ones to be skipped because they are disabled. */
586
			/* Then we can easily know and match them later when attempting to add dynamic gateways to the list. */
587
			$gateways_arr_temp[$gateway['name']] = $gateway;
588

    
589
			/* skip disabled gateways if the caller has not asked for them to be returned. */
590
			if (!($disabled === false && isset($gateway['disabled']))) {
591
				$gateways_arr[$gateway['name']] = $gateway;
592
			}
593
		}
594
	}
595
	unset($gateway);
596

    
597
	/* Loop through all interfaces with a gateway and add it to a array */
598
	if ($disabled == false) {
599
		$iflist = get_configured_interface_with_descr();
600
	} else {
601
		$iflist = get_configured_interface_with_descr(false, true);
602
	}
603

    
604
	/* Process/add dynamic v4 gateways. */
605
	foreach ($iflist as $ifname => $friendly) {
606
		if (!interface_has_gateway($ifname)) {
607
			continue;
608
		}
609

    
610
		if (empty($config['interfaces'][$ifname])) {
611
			continue;
612
		}
613

    
614
		$ifcfg = &$config['interfaces'][$ifname];
615
		if (!isset($ifcfg['enable'])) {
616
			continue;
617
		}
618

    
619
		if (!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr'])) {
620
			continue;
621
		}
622

    
623
		$ctype = "";
624
		switch ($ifcfg['ipaddr']) {
625
			case "dhcp":
626
			case "pppoe":
627
			case "pptp":
628
			case "ppp":
629
				$ctype = strtoupper($ifcfg['ipaddr']);
630
				break;
631
			default:
632
				$tunnelif = substr($ifcfg['if'], 0, 3);
633
				if (substr($ifcfg['if'], 0, 4) == "ovpn") {
634
					// if current iface is an ovpn server endpoint then check its type, skip tap only
635
					if (substr($ifcfg['if'], 4, 1) == 's') {
636
						$ovpnid = substr($ifcfg['if'], 5);
637
						if (is_array($config['openvpn']['openvpn-server'])) {
638
							foreach ($config['openvpn']['openvpn-server'] as & $ovpnserverconf) {
639
								if ($ovpnserverconf['vpnid'] == $ovpnid) {
640
									if ($ovpnserverconf['dev_mode'] == "tap") {
641
										continue 3;
642
									}
643
								}
644
							}
645
						}
646
					}
647
					$ctype = "VPNv4";
648
				} else if ($tunnelif == "gif" || $tunnelif == "gre") {
649
					$ctype = "TUNNELv4";
650
				}
651
				break;
652
		}
653
		$ctype = "_". strtoupper($ctype);
654

    
655
		$gateway = array();
656
		$gateway['dynamic'] = false;
657
		$gateway['ipprotocol'] = "inet";
658
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
659
		$gateway['interface'] = get_real_interface($ifname);
660
		$gateway['friendlyiface'] = $ifname;
661
		$gateway['name'] = "{$friendly}{$ctype}";
662
		$gateway['attribute'] = "system";
663

    
664
		if (($gateway['dynamic'] === "default") && ($found_defaultv4 == 0)) {
665
			$gateway['defaultgw'] = true;
666
			$gateway['dynamic'] = true;
667
			$found_defaultv4 = 1;
668
		}
669
		/* Loopback dummy for dynamic interfaces without a IP */
670
		if (!is_ipaddrv4($gateway['gateway']) && $gateway['dynamic'] == true) {
671
			$gateway['gateway'] = "dynamic";
672
		}
673

    
674
		/* automatically skip known static and dynamic gateways that were previously processed */
675
		foreach ($gateways_arr_temp as $gateway_item) {
676
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name'])&& ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
677
			    (($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))) {
678
				continue 2;
679
			}
680
		}
681

    
682
		if (is_ipaddrv4($gateway['gateway'])) {
683
			$gateway['monitor'] = $gateway['gateway'];
684
		}
685

    
686
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
687
		$gateways_arr[$gateway['name']] = $gateway;
688
	}
689
	unset($gateway);
690

    
691
	/* Process/add dynamic v6 gateways. */
692
	foreach ($iflist as $ifname => $friendly) {
693
		/* If the user has disabled IPv6, they probably don't want any IPv6 gateways. */
694
		if (!isset($config['system']['ipv6allow'])) {
695
			break;
696
		}
697

    
698
		if (!interface_has_gatewayv6($ifname)) {
699
			continue;
700
		}
701

    
702
		if (empty($config['interfaces'][$ifname])) {
703
			continue;
704
		}
705

    
706
		$ifcfg = &$config['interfaces'][$ifname];
707
		if (!isset($ifcfg['enable'])) {
708
			continue;
709
		}
710

    
711
		if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
712
			continue;
713
		}
714

    
715
		$ctype = "";
716
		switch ($ifcfg['ipaddrv6']) {
717
			case "slaac":
718
			case "dhcp6":
719
			case "6to4":
720
			case "6rd":
721
				$ctype = strtoupper($ifcfg['ipaddrv6']);
722
				break;
723
			default:
724
				$tunnelif = substr($ifcfg['if'], 0, 3);
725
				if (substr($ifcfg['if'], 0, 4) == "ovpn") {
726
					// if current iface is an ovpn server endpoint then check its type, skip tap only
727
					if (substr($ifcfg['if'], 4, 1) == 's') {
728
						$ovpnid = substr($ifcfg['if'], 5);
729
						if (is_array($config['openvpn']['openvpn-server'])) {
730
							foreach ($config['openvpn']['openvpn-server'] as & $ovpnserverconf) {
731
								if ($ovpnserverconf['vpnid'] == $ovpnid) {
732
									if ($ovpnserverconf['dev_mode'] == "tap") {
733
										continue 3;
734
									}
735
								}
736
							}
737
						}
738
					}
739
					$ctype = "VPNv6";
740
				} else if ($tunnelif == "gif" || $tunnelif == "gre") {
741
					$ctype = "TUNNELv6";
742
				}
743
				break;
744
		}
745
		$ctype = "_". strtoupper($ctype);
746

    
747
		$gateway = array();
748
		$gateway['dynamic'] = false;
749
		$gateway['ipprotocol'] = "inet6";
750
		$gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
751
		$gateway['interface'] = get_real_interface($ifname, "inet6");
752
		switch ($ifcfg['ipaddrv6']) {
753
			case "6rd":
754
			case "6to4":
755
				$gateway['dynamic'] = "default";
756
				break;
757
		}
758
		$gateway['friendlyiface'] = $ifname;
759
		$gateway['name'] = "{$friendly}{$ctype}";
760
		$gateway['attribute'] = "system";
761

    
762
		if (($gateway['dynamic'] === "default") && ($found_defaultv6 == 0)) {
763
			$gateway['defaultgw'] = true;
764
			$gateway['dynamic'] = true;
765
			$found_defaultv6 = 1;
766
		}
767

    
768
		/* Loopback dummy for dynamic interfaces without a IP */
769
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true) {
770
			$gateway['gateway'] = "dynamic";
771
		}
772

    
773
		/* automatically skip known static and dynamic gateways that were previously processed */
774
		foreach ($gateways_arr_temp as $gateway_item) {
775
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
776
			    (($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))) {
777
				continue 2;
778
			}
779
		}
780

    
781
		if (is_ipaddrv6($gateway['gateway'])) {
782
			$gateway['monitor'] = $gateway['gateway'];
783
		}
784

    
785
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
786
		$gateways_arr[$gateway['name']] = $gateway;
787
	}
788
	unset($gateway);
789

    
790
	/* FIXME: Should this be enabled.
791
	 * Some interface like wan might be default but have no info recorded
792
	 * the config. */
793
	/* this is a fallback if all else fails and we want to get packets out @smos */
794
	if ($found_defaultv4 == 0 || $found_defaultv6 == 0) {
795
		foreach ($gateways_arr as &$gateway) {
796
			if (($gateway['friendlyiface'] == "wan") && ($found_defaultv4 == 0) && (!isset($gateway['ipprotocol']) || ($gateway['ipprotocol'] == "inet"))) {
797
				if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgw")) {
798
					$gateway['defaultgw'] = true;
799
					$found_defaultv4 = 1;
800
				}
801
			}
802
			else if (($gateway['friendlyiface'] == "wan") && ($found_defaultv6 == 0) && ($gateway['ipprotocol'] == "inet6")) {
803
				if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgwv6")) {
804
					$gateway['defaultgw'] = true;
805
					$found_defaultv6 = 1;
806
				}
807
			}
808
		}
809
	}
810

    
811
	if ($localhost === true) {
812
		/* attach localhost for Null routes */
813
		$gwlo4 = array();
814
		$gwlo4['name'] = "Null4";
815
		$gwlo4['interface'] = "lo0";
816
		$gwlo4['ipprotocol'] = "inet";
817
		$gwlo4['gateway'] = "127.0.0.1";
818
		$gwlo6 = array();
819
		$gwlo6['name'] = "Null6";
820
		$gwlo6['interface'] = "lo0";
821
		$gwlo6['ipprotocol'] = "inet6";
822
		$gwlo6['gateway'] = "::1";
823
		$gateways_arr['Null4'] = $gwlo4;
824
		$gateways_arr['Null6'] = $gwlo6;
825
	}
826
	return($gateways_arr);
827
}
828

    
829
function fixup_default_gateway($ipprotocol, $gateways_status, $gateways_arr) {
830
	global $config, $g;
831
	/*
832
	 * NOTE: The code below is meant to replace the default gateway when it goes down.
833
	 *	This facilitates services running on pfSense itself and are not handled by a PBR to continue working.
834
	 */
835
	$upgw = '';
836
	$dfltgwname = '';
837
	$dfltgwdown = false;
838
	$dfltgwfound = false;
839
	foreach ($gateways_arr as $gwname => $gwsttng) {
840
		if (($gwsttng['ipprotocol'] == $ipprotocol) && isset($gwsttng['defaultgw'])) {
841
			$dfltgwfound = true;
842
			$dfltgwname = $gwname;
843
			if (!isset($gwsttng['monitor_disable']) && $gateways_status[$gwname]['status'] != "none") {
844
				$dfltgwdown = true;
845
			}
846
		}
847
		/* Keep a record of the last up gateway */
848
		/* XXX: Blacklist lan for now since it might cause issues to those who have a gateway set for it */
849
		if (empty($upgw) && ($gwsttng['ipprotocol'] == $ipprotocol) && (isset($gwsttng['monitor_disable']) || $gateways_status[$gwname]['status'] == "none") && $gwsttng[$gwname]['friendlyiface'] != "lan") {
850
			$upgw = $gwname;
851
		}
852
		if ($dfltgwdown == true && !empty($upgw)) {
853
			break;
854
		}
855
	}
856
	if ($dfltgwfound == false) {
857
		$gwname = convert_friendly_interface_to_friendly_descr("wan");
858
		if (!empty($gateways_status[$gwname]) && stristr($gateways_status[$gwname]['status'], "down")) {
859
			$dfltgwdown = true;
860
		}
861
	}
862
	if ($dfltgwdown == true && !empty($upgw)) {
863
		if ($gateways_arr[$upgw]['gateway'] == "dynamic") {
864
			$gateways_arr[$upgw]['gateway'] = get_interface_gateway($gateways_arr[$upgw]['friendlyiface']);
865
		}
866
		if (is_ipaddr($gateways_arr[$upgw]['gateway'])) {
867
			log_error("Default gateway down setting {$upgw} as default!");
868
			if (is_ipaddrv6($gateways_arr[$upgw]['gateway'])) {
869
				$inetfamily = "-inet6";
870
				if (is_linklocal($gateways_arr[$upgw]['gateway']) && get_ll_scope($gateways_arr[$upgw]['gateway']) == '') {
871
					$gateways_arr[$upgw]['gateway'] .= "%" . $gateways_arr[$upgw]['interface'];
872
				}
873
			} else {
874
				$inetfamily = "-inet";
875
			}
876
			mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$upgw]['gateway']}");
877
		}
878
	} else if (!empty($dfltgwname)) {
879
		$defaultgw = trim(exec("/sbin/route -n get -{$ipprotocol} default | /usr/bin/awk '/gateway:/ {print $2}'"), " \n");
880
		if ($ipprotocol == 'inet6' && !is_ipaddrv6($gateways_arr[$dfltgwname]['gateway'])) {
881
			return;
882
		}
883
		if ($ipprotocol == 'inet' && !is_ipaddrv4($gateways_arr[$dfltgwname]['gateway'])) {
884
			return;
885
		}
886
		if ($ipprotocol == 'inet6') {
887
			if (is_linklocal($gateways_arr[$upgw]['gateway']) && get_ll_scope($gateways_arr[$upgw]['gateway']) == '') {
888
				$gateways_arr[$upgw]['gateway'] .= "%" . $gateways_arr[$upgw]['interface'];
889
			}
890
			if (is_linklocal($gateways_arr[$dfltgwname]['gateway']) && get_ll_scope($gateways_arr[$dfltgwname]['gateway']) == '') {
891
				$gateways_arr[$dfltgwname]['gateway'] .= "%" . $gateways_arr[$dfltgwname]['interface'];
892
			}
893
		}
894
		if ($defaultgw != $gateways_arr[$dfltgwname]['gateway']) {
895
			mwexec("/sbin/route change -{$ipprotocol} default {$gateways_arr[$dfltgwname]['gateway']}");
896
		}
897
	}
898
}
899

    
900
/*
901
 * Return an array with all gateway groups with name as key
902
 * All gateway groups will be processed before returning the array.
903
 */
904
function return_gateway_groups_array() {
905
	global $config, $g;
906

    
907
	/* fetch the current gateways status */
908
	$gateways_status = return_gateways_status(true);
909
	$gateways_arr = return_gateways_array();
910
	$gateway_groups_array = array();
911

    
912
	if (isset($config['system']['gw_switch_default'])) {
913
		fixup_default_gateway("inet", $gateways_status, $gateways_arr);
914
		fixup_default_gateway("inet6", $gateways_status, $gateways_arr);
915
	}
916
	if (is_array($config['gateways']['gateway_group'])) {
917
		$viplist = get_configured_vip_list();
918
		foreach ($config['gateways']['gateway_group'] as $group) {
919
			$gateway_groups_array[$group['name']]['descr'] = $group['descr'];
920
			/* create array with group gateways members separated by tier */
921
			$tiers = array();
922
			$backupplan = array();
923
			$gwvip_arr = array();
924
			foreach ($group['item'] as $item) {
925
				list($gwname, $tier, $vipname) = explode("|", $item);
926

    
927
				if (is_ipaddr($viplist[$vipname])) {
928
					if (!is_array($gwvip_arr[$group['name']])) {
929
						$gwvip_arr[$group['name']] = array();
930
					}
931
					$gwvip_arr[$group['name']][$gwname] = $vipname;
932
				}
933

    
934
				/* Do it here rather than reiterating again the group in case no member is up. */
935
				if (!is_array($backupplan[$tier])) {
936
					$backupplan[$tier] = array();
937
				}
938
				$backupplan[$tier][] = $gwname;
939

    
940
				/* check if the gateway is available before adding it to the array */
941
				if (is_array($gateways_status[$gwname])) {
942
					$status = $gateways_status[$gwname];
943
					$gwdown = false;
944
					if (stristr($status['status'], "down")) {
945
						$msg = sprintf(gettext('MONITOR: %1$s is down, omitting from routing group %2$s'), $gwname, $group['name']);
946
						$gwdown = true;
947
					} else if (stristr($status['status'], "loss") && strstr($group['trigger'], "loss")) {
948
						/* packet loss */
949
						$msg = sprintf(gettext('MONITOR: %1$s has packet loss, omitting from routing group %2$s'), $gwname, $group['name']);
950
						$gwdown = true;
951
					} else if (stristr($status['status'], "delay") && strstr($group['trigger'] , "latency")) {
952
						/* high latency */
953
						$msg = sprintf(gettext('MONITOR: %1$s has high latency, omitting from routing group %2$s'), $gwname, $group['name']);
954
						$gwdown = true;
955
					}
956
					if ($gwdown == true) {
957
						log_error($msg);
958
						notify_via_growl($msg);
959
						notify_via_smtp($msg);
960
					} else {
961
						/* Online add member */
962
						if (!is_array($tiers[$tier])) {
963
							$tiers[$tier] = array();
964
						}
965
						$tiers[$tier][] = $gwname;
966
					}
967
				} else if (isset($gateways_arr[$gwname]['monitor_disable'])) {
968
					$tiers[$tier][] = $gwname;
969
				}
970
			}
971
			$tiers_count = count($tiers);
972
			if ($tiers_count == 0) {
973
				/* Oh dear, we have no members! Engage Plan B */
974
				if (!platform_booting()) {
975
					$msg = sprintf(gettext('Gateways status could not be determined, considering all as up/active. (Group: %s)'), $group['name']);
976
					log_error($msg);
977
					notify_via_growl($msg);
978
					//notify_via_smtp($msg);
979
				}
980
				$tiers = $backupplan;
981
			}
982
			/* sort the tiers array by the tier key */
983
			ksort($tiers);
984

    
985
			/* we do not really foreach the tiers as we stop after the first tier */
986
			foreach ($tiers as $tieridx => $tier) {
987
				/* process all gateways in this tier */
988
				foreach ($tier as $member) {
989
					/* determine interface gateway */
990
					if (isset($gateways_arr[$member])) {
991
						$gateway = $gateways_arr[$member];
992
						$int = $gateway['interface'];
993
						$gatewayip = "";
994
						if (is_ipaddr($gateway['gateway'])) {
995
							$gatewayip = $gateway['gateway'];
996
						} else if (!empty($int)) {
997
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
998
						}
999

    
1000
						if (!empty($int)) {
1001
							$gateway_groups_array[$group['name']]['ipprotocol'] = $gateway['ipprotocol'];
1002
							if (is_ipaddr($gatewayip)) {
1003
								$groupmember = array();
1004
								$groupmember['int'] = $int;
1005
								$groupmember['gwip'] = $gatewayip;
1006
								$groupmember['weight'] = isset($gateway['weight']) ? $gateway['weight'] : 1;
1007
								if (is_array($gwvip_arr[$group['name']]) && !empty($gwvip_arr[$group['name']][$member]))
1008
									$groupmember['vip'] = $gwvip_arr[$group['name']][$member];
1009
								$gateway_groups_array[$group['name']][] = $groupmember;
1010
							}
1011
						}
1012
					}
1013
				}
1014
				/* we should have the 1st available tier now, exit stage left */
1015
				if (count($gateway_groups_array[$group['name']]) > 0) {
1016
					break;
1017
				} else {
1018
					log_error(sprintf(gettext('GATEWAYS: Group %1$s did not have any gateways up on tier %2$s!'), $group['name'], $tieridx));
1019
				}
1020
			}
1021
		}
1022
	}
1023

    
1024
	return ($gateway_groups_array);
1025
}
1026

    
1027
/* Update DHCP WAN Interface ip address in gateway group item */
1028
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
1029
	global $config, $g;
1030
	foreach ($config['gateways']['gateway_item'] as & $gw) {
1031
		if ($gw['interface'] == $interface) {
1032
			$current_gw = get_interface_gateway($interface);
1033
			if ($gw['gateway'] <> $current_gw) {
1034
				$gw['gateway'] = $current_gw;
1035
				$changed = true;
1036
			}
1037
		}
1038
	}
1039
	if ($changed && $current_gw) {
1040
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interface, $current_gw));
1041
	}
1042
}
1043

    
1044
function lookup_gateway_ip_by_name($name, $disabled = false) {
1045

    
1046
	$gateways_arr = return_gateways_array($disabled, true);
1047
	foreach ($gateways_arr as $gname => $gw) {
1048
		if ($gw['name'] === $name || $gname === $name) {
1049
			return $gw['gateway'];
1050
		}
1051
	}
1052

    
1053
	return false;
1054
}
1055

    
1056
function lookup_gateway_monitor_ip_by_name($name) {
1057

    
1058
	$gateways_arr = return_gateways_array(false, true);
1059
	if (!empty($gateways_arr[$name])) {
1060
		$gateway = $gateways_arr[$name];
1061
		if (!is_ipaddr($gateway['monitor'])) {
1062
			return $gateway['gateway'];
1063
		}
1064

    
1065
		return $gateway['monitor'];
1066
	}
1067

    
1068
	return (false);
1069
}
1070

    
1071
function lookup_gateway_interface_by_name($name) {
1072

    
1073
	$gateways_arr = return_gateways_array(false, true);
1074
	if (!empty($gateways_arr[$name])) {
1075
		$interfacegw = $gateways_arr[$name]['friendlyiface'];
1076
		return ($interfacegw);
1077
	}
1078

    
1079
	return (false);
1080
}
1081

    
1082
function get_interface_gateway($interface, &$dynamic = false) {
1083
	global $config, $g;
1084

    
1085
	if (substr($interface, 0, 4) == '_vip') {
1086
		$interface = get_configured_vip_interface($interface);
1087
		if (substr($interface, 0, 4) == '_vip') {
1088
			$interface = get_configured_vip_interface($interface);
1089
		}
1090
	}
1091

    
1092
	$gw = NULL;
1093
	$gwcfg = $config['interfaces'][$interface];
1094
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
1095
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1096
			if (($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
1097
				$gw = $gateway['gateway'];
1098
				break;
1099
			}
1100
		}
1101
	}
1102

    
1103
	// for dynamic interfaces we handle them through the $interface_router file.
1104
	if (($gw == NULL || !is_ipaddrv4($gw)) && !is_ipaddrv4($gwcfg['ipaddr'])) {
1105
		$realif = get_real_interface($interface);
1106
		if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1107
			$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
1108
			$dynamic = true;
1109
		}
1110
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw")) {
1111
			$dynamic = "default";
1112
		}
1113

    
1114
	}
1115

    
1116
	/* return gateway */
1117
	return ($gw);
1118
}
1119

    
1120
function get_interface_gateway_v6($interface, &$dynamic = false) {
1121
	global $config, $g;
1122

    
1123
	if (substr($interface, 0, 4) == '_vip') {
1124
		$interface = get_configured_vip_interface($interface);
1125
		if (substr($interface, 0, 4) == '_vip') {
1126
			$interface = get_configured_vip_interface($interface);
1127
		}
1128
	}
1129

    
1130
	$gw = NULL;
1131
	$gwcfg = $config['interfaces'][$interface];
1132
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
1133
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1134
			if (($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
1135
				$gw = $gateway['gateway'];
1136
				break;
1137
			}
1138
		}
1139
	}
1140

    
1141
	// for dynamic interfaces we handle them through the $interface_router file.
1142
	if (($gw == NULL || !is_ipaddrv6($gw)) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
1143
		$realif = get_real_interface($interface);
1144
		if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
1145
			$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
1146
			$dynamic = true;
1147
		}
1148
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6")) {
1149
			$dynamic = "default";
1150
		}
1151
	}
1152
	/* return gateway */
1153
	return ($gw);
1154
}
1155

    
1156
/* Check a IP address against a gateway IP or name
1157
 * to verify it's address family */
1158
function validate_address_family($ipaddr, $gwname, $disabled = false) {
1159
	$v4ip = false;
1160
	$v6ip = false;
1161
	$v4gw = false;
1162
	$v6gw = false;
1163

    
1164
	if (is_ipaddrv4($ipaddr)) {
1165
		$v4ip = true;
1166
	}
1167
	if (is_ipaddrv6($ipaddr)) {
1168
		$v6ip = true;
1169
	}
1170
	if (is_ipaddrv4($gwname)) {
1171
		$v4gw = true;
1172
	}
1173
	if (is_ipaddrv6($gwname)) {
1174
		$v6gw = true;
1175
	}
1176

    
1177
	if ($v4ip && $v4gw) {
1178
		return true;
1179
	}
1180
	if ($v6ip && $v6gw) {
1181
		return true;
1182
	}
1183

    
1184
	/* still no match, carry on, lookup gateways */
1185
	if (is_ipaddrv4(lookup_gateway_ip_by_name($gwname, $disabled))) {
1186
		$v4gw = true;
1187
	}
1188
	if (is_ipaddrv6(lookup_gateway_ip_by_name($gwname, $disabled))) {
1189
		$v6gw = true;
1190
	}
1191

    
1192
	$gw_array = return_gateways_array();
1193
	if (is_array($gw_array[$gwname])) {
1194
		switch ($gw_array[$gwname]['ipprotocol']) {
1195
			case "inet":
1196
				$v4gw = true;
1197
				break;
1198
			case "inet6":
1199
				$v6gw = true;
1200
				break;
1201
		}
1202
	}
1203

    
1204
	if ($v4ip && $v4gw) {
1205
		return true;
1206
	}
1207
	if ($v6ip && $v6gw) {
1208
		return true;
1209
	}
1210

    
1211
	return false;
1212
}
1213

    
1214
/* check if a interface is part of a gateway group */
1215
function interface_gateway_group_member($interface) {
1216
	global $config;
1217

    
1218
	if (is_array($config['gateways']['gateway_group'])) {
1219
		$groups = $config['gateways']['gateway_group'];
1220
	} else {
1221
		return false;
1222
	}
1223

    
1224
	$gateways_arr = return_gateways_array(false, true);
1225
	foreach ($groups as $group) {
1226
		if (is_array($group['item'])) {
1227
			foreach ($group['item'] as $item) {
1228
				$elements = explode("|", $item);
1229
				$gwname = $elements[0];
1230
				if ($interface == $gateways_arr[$gwname]['interface']) {
1231
					unset($gateways_arr);
1232
					return true;
1233
				}
1234
			}
1235
		}
1236
	}
1237
	unset($gateways_arr);
1238

    
1239
	return false;
1240
}
1241

    
1242
function gateway_is_gwgroup_member($name) {
1243
	global $config;
1244

    
1245
	if (is_array($config['gateways']['gateway_group'])) {
1246
		$groups = $config['gateways']['gateway_group'];
1247
	} else {
1248
		return false;
1249
	}
1250

    
1251
	$members = array();
1252
	foreach ($groups as $group) {
1253
		if (is_array($group['item'])) {
1254
			foreach ($group['item'] as $item) {
1255
				$elements = explode("|", $item);
1256
				$gwname = $elements[0];
1257
				if ($name == $elements[0]) {
1258
					$members[] = $group['name'];
1259
				}
1260
			}
1261
		}
1262
	}
1263

    
1264
	return $members;
1265
}
1266
?>
(24-24/65)