Project

General

Profile

Download (39.4 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
	gwlb.inc
4
	Copyright (C) 2008 Bill Marquette, Seth Mos
5
	Copyright (C) 2010 Ermal Luçi
6
	All rights reserved.
7

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

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

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

    
18
	THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
19
	INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
20
	AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21
	AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
22
	OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23
	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24
	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25
	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26
	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
	POSSIBILITY OF SUCH DAMAGE.
28

    
29
	pfSense_BUILDER_BINARIES:	/sbin/route	/usr/local/sbin/apinger
30
	pfSense_MODULE:	routing
31

    
32
 */
33
require_once("config.inc");
34
require_once("rrd.inc");
35

    
36
/* Returns an array of default values used for apinger.conf */
37
function return_apinger_defaults() {
38
	return array(
39
		"latencylow" => "200",
40
		"latencyhigh" => "500",
41
		"losslow" => "10",
42
		"losshigh" => "20",
43
		"interval" => "1",
44
		"down" => "10",
45
		"avg_delay_samples" => "10",
46
		"avg_loss_samples" => "50",
47
		"avg_loss_delay_samples" => "20");
48
}
49

    
50
/*
51
 * Creates monitoring configuration file and
52
 * adds appropriate static routes.
53
 */
54
function setup_gateways_monitor() {
55
	global $config, $g;
56

    
57
	$gateways_arr = return_gateways_array();
58
	if (!is_array($gateways_arr)) {
59
		log_error("No gateways to monitor. Apinger will not be run.");
60
		killbypid("{$g['varrun_path']}/apinger.pid");
61
		@unlink("{$g['varrun_path']}/apinger.status");
62
		return;
63
	}
64

    
65
	$apinger_debug = "";
66
	if (isset($config['system']['apinger_debug'])) {
67
		$apinger_debug = "debug on";
68
	}
69

    
70
	$apinger_default = return_apinger_defaults();
71
	$apingerconfig = <<<EOD
72

    
73
# pfSense apinger configuration file. Automatically Generated!
74

    
75
{$apinger_debug}
76

    
77
## User and group the pinger should run as
78
user "root"
79
group "wheel"
80

    
81
## Mailer to use (default: "/usr/lib/sendmail -t")
82
#mailer "/var/qmail/bin/qmail-inject"
83

    
84
## Location of the pid-file (default: "/var/run/apinger.pid")
85
pid_file "{$g['varrun_path']}/apinger.pid"
86

    
87
## Format of timestamp (%s macro) (default: "%b %d %H:%M:%S")
88
#timestamp_format "%Y%m%d%H%M%S"
89

    
90
status {
91
	## File where the status information should be written to
92
	file "{$g['varrun_path']}/apinger.status"
93
	## Interval between file updates
94
	## when 0 or not set, file is written only when SIGUSR1 is received
95
	interval 5s
96
}
97

    
98
########################################
99
# RRDTool status gathering configuration
100
# Interval between RRD updates
101
rrd interval 60s;
102

    
103
## These parameters can be overridden in a specific alarm configuration
104
alarm default {
105
	command on "/usr/local/sbin/pfSctl -c 'service reload dyndns %T' -c 'service reload ipsecdns' -c 'service reload openvpn %T' -c 'filter reload' "
106
	command off "/usr/local/sbin/pfSctl -c 'service reload dyndns %T' -c 'service reload ipsecdns' -c 'service reload openvpn %T' -c 'filter reload' "
107
	combine 10s
108
}
109

    
110
## "Down" alarm definition.
111
## This alarm will be fired when target doesn't respond for 30 seconds.
112
alarm down "down" {
113
	time {$apinger_default['down']}s
114
}
115

    
116
## "Delay" alarm definition.
117
## This alarm will be fired when responses are delayed more than 200ms
118
## it will be canceled, when the delay drops below 100ms
119
alarm delay "delay" {
120
	delay_low {$apinger_default['latencylow']}ms
121
	delay_high {$apinger_default['latencyhigh']}ms
122
}
123

    
124
## "Loss" alarm definition.
125
## This alarm will be fired when packet loss goes over 20%
126
## it will be canceled, when the loss drops below 10%
127
alarm loss "loss" {
128
	percent_low {$apinger_default['losslow']}
129
	percent_high {$apinger_default['losshigh']}
130
}
131

    
132
target default {
133
	## How often the probe should be sent
134
	interval {$apinger_default['interval']}s
135

    
136
	## How many replies should be used to compute average delay
137
	## for controlling "delay" alarms
138
	avg_delay_samples {$apinger_default['avg_delay_samples']}
139

    
140
	## How many probes should be used to compute average loss
141
	avg_loss_samples {$apinger_default['avg_loss_samples']}
142

    
143
	## The delay (in samples) after which loss is computed
144
	## without this delays larger than interval would be treated as loss
145
	avg_loss_delay_samples {$apinger_default['avg_loss_delay_samples']}
146

    
147
	## Names of the alarms that may be generated for the target
148
	alarms "down","delay","loss"
149

    
150
	## Location of the RRD
151
	#rrd file "{$g['vardb_path']}/rrd/apinger-%t.rrd"
152
}
153

    
154
EOD;
155

    
156
	$monitor_ips = array();
157
	foreach ($gateways_arr as $name => $gateway) {
158
		/* Do not monitor if such was requested */
159
		if (isset($gateway['monitor_disable'])) {
160
			continue;
161
		}
162
		if (empty($gateway['monitor']) || !is_ipaddr($gateway['monitor'])) {
163
			if (is_ipaddr($gateway['gateway'])) {
164
				$gateway['monitor'] = $gateway['gateway'];
165
			} else { /* No chance to get an ip to monitor skip target. */
166
				continue;
167
			}
168
		}
169

    
170
		/* if the monitor address is already used before, skip */
171
		if (in_array($gateway['monitor'], $monitor_ips)) {
172
			continue;
173
		}
174

    
175
		/* Interface ip is needed since apinger will bind a socket to it.
176
		 * However the config GUI should already have checked this and when
177
		 * PPoE is used the IP address is set to "dynamic". So using is_ipaddrv4
178
		 * or is_ipaddrv6 to identify packet type would be wrong, especially as
179
		 * further checks (that can cope with the "dynamic" case) are present inside
180
		 * the if block. So using $gateway['ipprotocol'] is the better option.
181
		 */
182
		if ($gateway['ipprotocol'] == "inet") { // This is an IPv4 gateway...
183
			$gwifip = find_interface_ip($gateway['interface'], true);
184
			if (!is_ipaddrv4($gwifip)) {
185
				continue; //Skip this target
186
			}
187

    
188
			if ($gwifip == "0.0.0.0") {
189
				continue; //Skip this target - the gateway is still waiting for DHCP
190
			}
191

    
192
			/*
193
			 * If the gateway is the same as the monitor we do not add a
194
			 * route as this will break the routing table.
195
			 * Add static routes for each gateway with their monitor IP
196
			 * not strictly necessary but is a added level of protection.
197
			 */
198
			if (is_ipaddrv4($gateway['gateway']) && $gateway['monitor'] != $gateway['gateway']) {
199
				log_error("Removing static route for monitor {$gateway['monitor']} and adding a new route through {$gateway['gateway']}");
200
				if (interface_isppp_type($gateway['friendlyiface'])) {
201
					mwexec("/sbin/route change -host " . escapeshellarg($gateway['monitor']) .
202
						" -iface " . escapeshellarg($gateway['interface']), true);
203
				} else {
204
					mwexec("/sbin/route change -host " . escapeshellarg($gateway['monitor']) .
205
						" " . escapeshellarg($gateway['gateway']), true);
206
				}
207

    
208
				pfSense_kill_states("0.0.0.0/0", $gateway['monitor'], $gateway['interface'], "icmp");
209
			}
210
		} else if ($gateway['ipprotocol'] == "inet6") { // This is an IPv6 gateway...
211
			if ($gateway['monitor'] == $gateway['gateway']) {
212
				/* link locals really need a different src ip */
213
				if (is_linklocal($gateway['gateway'])) {
214
					if (!strpos($gateway['gateway'], '%')) {
215
						$gateway['gateway'] .= '%' . $gateway['interface'];
216
					}
217
					$gwifip = find_interface_ipv6_ll($gateway['interface'], true);
218
				} else {
219
					$gwifip = find_interface_ipv6($gateway['interface'], true);
220
				}
221
			} else {
222
				/* 'monitor' has been set, so makes sure it has precedence over
223
				 * 'gateway' in defining the source IP. Otherwise if 'gateway'
224
				 * is a local link and 'monitor' is global routable then the
225
				 * ICMP6 response would not find its way back home...
226
				 */
227
				$gwifip = find_interface_ipv6($gateway['interface'], true);
228
			}
229

    
230
			/* Make sure srcip and target have scope defined when they are ll */
231
			if (is_linklocal($gwifip) && !strpos($gwifip, '%')) {
232
				$gwifip .= '%' . $gateway['interface'];
233
			}
234
			if (is_linklocal($gateway['monitor']) && !strpos($gateway['monitor'], '%')) {
235
				$gateway['monitor'] .= "%{$gateway['interface']}";
236
			}
237

    
238
			if (!is_ipaddrv6($gwifip)) {
239
				continue; //Skip this target
240
			}
241

    
242
			/*
243
			 * If the gateway is the same as the monitor we do not add a
244
			 * route as this will break the routing table.
245
			 * Add static routes for each gateway with their monitor IP
246
			 * not strictly necessary but is a added level of protection.
247
			 */
248
			if ($gateway['gateway'] != $gateway['monitor']) {
249
				log_error("Removing static route for monitor {$gateway['monitor']} and adding a new route through {$gateway['gateway']}");
250
				if (interface_isppp_type($gateway['friendlyiface'])) {
251
					mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gateway['monitor']) .
252
						" -iface " . escapeshellarg($gateway['interface']), true);
253
				} else {
254
					mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gateway['monitor']) .
255
						" " . escapeshellarg($gateway['gateway']), true);
256
				}
257

    
258
				pfSense_kill_states("::0.0.0.0/0", $gateway['monitor'], $gateway['interface'], "icmpv6");
259
			}
260
		} else {
261
			continue;
262
		}
263

    
264
		$monitor_ips[] = $gateway['monitor'];
265
		$apingercfg = "target \"{$gateway['monitor']}\" {\n";
266
		$apingercfg .= "	description \"{$name}\"\n";
267
		$apingercfg .= "	srcip \"{$gwifip}\"\n";
268

    
269
		## How often the probe should be sent
270
		if (!empty($gateway['interval']) && is_numeric($gateway['interval'])) {
271
			$interval = intval($gateway['interval']);	# Restrict to Integer
272
			if ($interval < 1) {
273
				$interval = 1;	# Minimum
274
			}
275
			if ($interval != $apinger_default['interval']) {	# If not default value
276
				$apingercfg .= "	interval " . $interval . "s\n";
277
			}
278
		}
279

    
280
		## How many replies should be used to compute average delay
281
		## for controlling "delay" alarms
282
		if (!empty($gateway['avg_delay_samples']) && is_numeric($gateway['avg_delay_samples'])) {
283
			$avg_delay_samples = intval($gateway['avg_delay_samples']);	# Restrict to Integer
284
			if ($avg_delay_samples < 1) {
285
				$avg_delay_samples = 1;	# Minimum
286
			}
287
			if ($avg_delay_samples != $apinger_default['avg_delay_samples']) {	# If not default value
288
				$apingercfg .= "	avg_delay_samples " . $avg_delay_samples . "\n";
289
			}
290
		}
291

    
292
		## How many probes should be used to compute average loss
293
		if (!empty($gateway['avg_loss_samples']) && is_numeric($gateway['avg_loss_samples'])) {
294
			$avg_loss_samples = intval($gateway['avg_loss_samples']);	# Restrict to Integer
295
			if ($avg_loss_samples < 1) {
296
				$avg_loss_samples = 1;	# Minimum
297
			}
298
			if ($avg_loss_samples != $apinger_default['avg_loss_samples']) { # If not default value
299
				$apingercfg .= "	avg_loss_samples " . $avg_loss_samples . "\n";
300
			}
301
		}
302

    
303
		## The delay (in samples) after which loss is computed
304
		## without this delays larger than interval would be treated as loss
305
		if (!empty($gateway['avg_loss_delay_samples']) && is_numeric($gateway['avg_loss_delay_samples'])) {
306
			$avg_loss_delay_samples = intval($gateway['avg_loss_delay_samples']);	# Restrict to Integer
307
			if ($avg_loss_delay_samples < 1) {
308
				$avg_loss_delay_samples = 1;	# Minimum
309
			}
310
			if ($avg_loss_delay_samples != $apinger_default['avg_loss_delay_samples']) { # If not default value
311
				$apingercfg .= "	avg_loss_delay_samples " . $avg_loss_delay_samples . "\n";
312
			}
313
		}
314

    
315
		$alarms = "";
316
		$alarmscfg = "";
317
		$override = false;
318
		if (!empty($gateway['losslow'])) {
319
			$alarmscfg .= "alarm loss \"{$name}loss\" {\n";
320
			$alarmscfg .= "\tpercent_low {$gateway['losslow']}\n";
321
			$alarmscfg .= "\tpercent_high {$gateway['losshigh']}\n";
322
			$alarmscfg .= "}\n";
323
			$alarms .= "\"{$name}loss\"";
324
			$override = true;
325
		} else {
326
			if ($override == true) {
327
				$alarms .= ",";
328
			}
329
			$alarms .= "\"loss\"";
330
			$override = true;
331
		}
332
		if (!empty($gateway['latencylow'])) {
333
			$alarmscfg .= "alarm delay \"{$name}delay\" {\n";
334
			$alarmscfg .= "\tdelay_low {$gateway['latencylow']}ms\n";
335
			$alarmscfg .= "\tdelay_high {$gateway['latencyhigh']}ms\n";
336
			$alarmscfg .= "}\n";
337
			if ($override == true) {
338
				$alarms .= ",";
339
			}
340
			$alarms .= "\"{$name}delay\"";
341
			$override = true;
342
		} else {
343
			if ($override == true) {
344
				$alarms .= ",";
345
			}
346
			$alarms .= "\"delay\"";
347
			$override = true;
348
		}
349
		if (!empty($gateway['down'])) {
350
			$alarmscfg .= "alarm down \"{$name}down\" {\n";
351
			$alarmscfg .= "\ttime {$gateway['down']}s\n";
352
			$alarmscfg .= "}\n";
353
			if ($override == true) {
354
				$alarms .= ",";
355
			}
356
			$alarms .= "\"{$name}down\"";
357
			$override = true;
358
		} else {
359
			if ($override == true) {
360
				$alarms .= ",";
361
			}
362
			$alarms .= "\"down\"";
363
			$override = true;
364
		}
365
		if ($override == true) {
366
			$apingercfg .= "\talarms override {$alarms};\n";
367
		}
368

    
369
		if (isset($gateway['force_down'])) {
370
			$apingercfg .= "\tforce_down on\n";
371
		}
372

    
373
		$apingercfg .= "	rrd file \"{$g['vardb_path']}/rrd/{$gateway['name']}-quality.rrd\"\n";
374
		$apingercfg .= "}\n";
375
		$apingercfg .= "\n";
376

    
377
		$apingerconfig .= $alarmscfg;
378
		$apingerconfig .= $apingercfg;
379

    
380
		# Create gateway quality RRD with settings more suitable for pfSense graph set,
381
		# since apinger uses default step (300; 5 minutes) and other settings that don't
382
		# match the pfSense gateway quality graph set.
383
		create_gateway_quality_rrd("{$g['vardb_path']}/rrd/{$gateway['name']}-quality.rrd");
384
	}
385
	@file_put_contents("{$g['varetc_path']}/apinger.conf", $apingerconfig);
386
	unset($apingerconfig);
387

    
388
	/* Restart apinger process */
389
	if (isvalidpid("{$g['varrun_path']}/apinger.pid")) {
390
		sigkillbypid("{$g['varrun_path']}/apinger.pid", "HUP");
391
	} else {
392
		/* start a new apinger process */
393
		@unlink("{$g['varrun_path']}/apinger.status");
394
		sleep(1);
395
		mwexec_bg("/usr/local/sbin/apinger -c {$g['varetc_path']}/apinger.conf");
396
		sleep(1);
397
		sigkillbypid("{$g['varrun_path']}/apinger.pid", "USR1");
398
	}
399

    
400
	return 0;
401
}
402

    
403
/* return the status of the apinger targets as a array */
404
function return_gateways_status($byname = false) {
405
	global $config, $g;
406

    
407
	$apingerstatus = array();
408
	/* Always get the latest status from apinger */
409
	if (file_exists("{$g['varrun_path']}/apinger.pid")) {
410
		sigkillbypid("{$g['varrun_path']}/apinger.pid", "USR1");
411
	}
412
	if (file_exists("{$g['varrun_path']}/apinger.status")) {
413
		$apingerstatus = file("{$g['varrun_path']}/apinger.status");
414
	} else {
415
		$apingerstatus = array();
416
	}
417

    
418
	$status = array();
419
	foreach ($apingerstatus as $line) {
420
		$info = explode("|", $line);
421
		if ($byname == false) {
422
			$target = $info[0];
423
		} else {
424
			$target = $info[2];
425
		}
426

    
427
		$status[$target] = array();
428
		$status[$target]['monitorip'] = $info[0];
429
		$status[$target]['srcip'] = $info[1];
430
		$status[$target]['name'] = $info[2];
431
		$status[$target]['lastcheck'] = $info[5] ? date('r', $info[5]) : date('r');
432
		$status[$target]['delay'] = empty($info[6]) ? "0ms" : round($info[6], 1) ."ms" ;
433
		$status[$target]['loss'] = empty($info[7]) ? "0.0%" : round($info[7], 1) . "%";
434
		$status[$target]['status'] = trim($info[8]);
435
	}
436

    
437
	/* tack on any gateways that have monitoring disabled
438
	 * or are down, which could cause gateway groups to fail */
439
	$gateways_arr = return_gateways_array();
440
	foreach ($gateways_arr as $gwitem) {
441
		if (!isset($gwitem['monitor_disable'])) {
442
			continue;
443
		}
444
		if (!is_ipaddr($gwitem['monitorip'])) {
445
			$realif = $gwitem['interface'];
446
			$tgtip = get_interface_gateway($realif);
447
			if (!is_ipaddr($tgtip)) {
448
				$tgtip = "none";
449
			}
450
			$srcip = find_interface_ip($realif);
451
		} else {
452
			$tgtip = $gwitem['monitorip'];
453
			$srcip = find_interface_ip($realif);
454
		}
455
		if ($byname == true) {
456
			$target = $gwitem['name'];
457
		} else {
458
			$target = $tgtip;
459
		}
460

    
461
		/* failsafe for down interfaces */
462
		if ($target == "none") {
463
			$target = $gwitem['name'];
464
			$status[$target]['name'] = $gwitem['name'];
465
			$status[$target]['lastcheck'] = date('r');
466
			$status[$target]['delay'] = "0.0ms";
467
			$status[$target]['loss'] = "100.0%";
468
			$status[$target]['status'] = "down";
469
		} else {
470
			$status[$target]['monitorip'] = $tgtip;
471
			$status[$target]['srcip'] = $srcip;
472
			$status[$target]['name'] = $gwitem['name'];
473
			$status[$target]['lastcheck'] = date('r');
474
			$status[$target]['delay'] = "0.0ms";
475
			$status[$target]['loss'] = "0.0%";
476
			$status[$target]['status'] = "none";
477
		}
478
	}
479
	return($status);
480
}
481

    
482
/* Return all configured gateways on the system */
483
function return_gateways_array($disabled = false, $localhost = false, $inactive = false) {
484
	global $config, $g;
485

    
486
	$gateways_arr = array();
487
	$gateways_arr_temp = array();
488

    
489
	$found_defaultv4 = 0;
490
	$found_defaultv6 = 0;
491

    
492
	// Ensure the interface cache is up to date first
493
	$interfaces = get_interface_arr(true);
494
	$interfaces_v4 = array();
495
	$interfaces_v6 = array();
496

    
497
	$i = -1;
498
	/* Process/add all the configured gateways. */
499
	if (is_array($config['gateways']['gateway_item'])) {
500
		foreach ($config['gateways']['gateway_item'] as $gateway) {
501
			/* Increment it here to do not skip items */
502
			$i++;
503

    
504
			if (empty($config['interfaces'][$gateway['interface']])) {
505
				if ($inactive === false) {
506
					continue;
507
				} else {
508
					$gateway['inactive'] = true;
509
				}
510
			}
511
			$wancfg = $config['interfaces'][$gateway['interface']];
512

    
513
			/* skip disabled interfaces */
514
			if ($disabled === false && (!isset($wancfg['enable']))) {
515
				continue;
516
			}
517

    
518
			/* if the gateway is dynamic and we can find the IPv4, Great! */
519
			if (empty($gateway['gateway']) || $gateway['gateway'] == "dynamic") {
520
				if ($gateway['ipprotocol'] == "inet") {
521
					/* we know which interfaces is dynamic, this should be made a function */
522
					$gateway['gateway'] = get_interface_gateway($gateway['interface']);
523
					/* no IP address found, set to dynamic */
524
					if (!is_ipaddrv4($gateway['gateway'])) {
525
						$gateway['gateway'] = "dynamic";
526
					}
527
					$gateway['dynamic'] = true;
528
				}
529

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

    
550
			if (isset($gateway['monitor_disable'])) {
551
				$gateway['monitor_disable'] = true;
552
			} else if (empty($gateway['monitor'])) {
553
				$gateway['monitor'] = $gateway['gateway'];
554
			}
555

    
556
			$gateway['friendlyiface'] = $gateway['interface'];
557

    
558
			/* special treatment for tunnel interfaces */
559
			if ($gateway['ipprotocol'] == "inet6") {
560
				$gateway['interface'] = get_real_interface($gateway['interface'], "inet6", false, false);
561
				$interfaces_v6[$gateway['friendlyiface']] = $gateway['friendlyiface'];
562
			} else {
563
				$gateway['interface'] = get_real_interface($gateway['interface'], "all", false, false);
564
				$interfaces_v4[$gateway['friendlyiface']] = $gateway['friendlyiface'];
565
			}
566

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

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

    
584
			/* skip disabled gateways if the caller has not asked for them to be returned. */
585
			if (!($disabled === false && isset($gateway['disabled']))) {
586
				$gateways_arr[$gateway['name']] = $gateway;
587
			}
588
		}
589
	}
590
	unset($gateway);
591

    
592
	/* Loop through all interfaces with a gateway and add it to a array */
593
	if ($disabled == false) {
594
		$iflist = get_configured_interface_with_descr();
595
	} else {
596
		$iflist = get_configured_interface_with_descr(false, true);
597
	}
598

    
599
	/* Process/add dynamic v4 gateways. */
600
	foreach ($iflist as $ifname => $friendly) {
601
		if (!interface_has_gateway($ifname)) {
602
			continue;
603
		}
604

    
605
		if (empty($config['interfaces'][$ifname])) {
606
			continue;
607
		}
608

    
609
		$ifcfg = &$config['interfaces'][$ifname];
610
		if (!isset($ifcfg['enable'])) {
611
			continue;
612
		}
613

    
614
		if (!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr'])) {
615
			continue;
616
		}
617

    
618
		if (isset($interfaces_v4[$ifname])) {
619
			continue;
620
		}
621

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

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

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

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

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

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

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

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

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

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

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

    
714
		if (isset($interfaces_v6[$ifname])) {
715
			continue;
716
		}
717

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

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

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

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

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

    
784
		if (is_ipaddrv6($gateway['gateway'])) {
785
			$gateway['monitor'] = $gateway['gateway'];
786
		}
787

    
788
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
789
		$gateways_arr[$gateway['name']] = $gateway;
790
	}
791
	unset($gateway);
792

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

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

    
832
function fixup_default_gateway($ipprotocol, $gateways_status, $gateways_arr) {
833
	global $config, $g;
834
	/*
835
	 * NOTE: The code below is meant to replace the default gateway when it goes down.
836
	 *	This facilitates services running on pfSense itself and are not handled by a PBR to continue working.
837
	 */
838
	$upgw = '';
839
	$dfltgwname = '';
840
	$dfltgwdown = false;
841
	$dfltgwfound = false;
842
	foreach ($gateways_arr as $gwname => $gwsttng) {
843
		if (($gwsttng['ipprotocol'] == $ipprotocol) && isset($gwsttng['defaultgw'])) {
844
			$dfltgwfound = true;
845
			$dfltgwname = $gwname;
846
			if (!isset($gwsttng['monitor_disable']) && $gateways_status[$gwname]['status'] != "none") {
847
				$dfltgwdown = true;
848
			}
849
		}
850
		/* Keep a record of the last up gateway */
851
		/* XXX: Blacklist lan for now since it might cause issues to those who have a gateway set for it */
852
		if (empty($upgw) && ($gwsttng['ipprotocol'] == $ipprotocol) && (isset($gwsttng['monitor_disable']) || $gateways_status[$gwname]['status'] == "none") && $gwsttng[$gwname]['friendlyiface'] != "lan") {
853
			$upgw = $gwname;
854
		}
855
		if ($dfltgwdown == true && !empty($upgw)) {
856
			break;
857
		}
858
	}
859
	if ($dfltgwfound == false) {
860
		$gwname = convert_friendly_interface_to_friendly_descr("wan");
861
		if (!empty($gateways_status[$gwname]) && stristr($gateways_status[$gwname]['status'], "down")) {
862
			$dfltgwdown = true;
863
		}
864
	}
865
	if ($dfltgwdown == true && !empty($upgw)) {
866
		if ($gateways_arr[$upgw]['gateway'] == "dynamic") {
867
			$gateways_arr[$upgw]['gateway'] = get_interface_gateway($gateways_arr[$upgw]['friendlyiface']);
868
		}
869
		if (is_ipaddr($gateways_arr[$upgw]['gateway'])) {
870
			log_error("Default gateway down setting {$upgw} as default!");
871
			if (is_ipaddrv6($gateways_arr[$upgw]['gateway'])) {
872
				$inetfamily = "-inet6";
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 ($defaultgw != $gateways_arr[$dfltgwname]['gateway']) {
887
			mwexec("/sbin/route change -{$ipprotocol} default {$gateways_arr[$dfltgwname]['gateway']}");
888
		}
889
	}
890
}
891

    
892
/*
893
 * Return an array with all gateway groups with name as key
894
 * All gateway groups will be processed before returning the array.
895
 */
896
function return_gateway_groups_array() {
897
	global $config, $g;
898

    
899
	/* fetch the current gateways status */
900
	$gateways_status = return_gateways_status(true);
901
	$gateways_arr = return_gateways_array();
902
	$gateway_groups_array = array();
903

    
904
	if (isset($config['system']['gw_switch_default'])) {
905
		fixup_default_gateway("inet", $gateways_status, $gateways_arr);
906
		fixup_default_gateway("inet6", $gateways_status, $gateways_arr);
907
	}
908
	if (is_array($config['gateways']['gateway_group'])) {
909
		$carplist = get_configured_carp_interface_list();
910
		foreach ($config['gateways']['gateway_group'] as $group) {
911
			/* create array with group gateways members separated by tier */
912
			$tiers = array();
913
			$backupplan = array();
914
			$gwvip_arr = array();
915
			foreach ($group['item'] as $item) {
916
				list($gwname, $tier, $vipname) = explode("|", $item);
917

    
918
				if (is_ipaddr($carplist[$vipname])) {
919
					if (!is_array($gwvip_arr[$group['name']])) {
920
						$gwvip_arr[$group['name']] = array();
921
					}
922
					$gwvip_arr[$group['name']][$gwname] = $vipname;
923
				}
924

    
925
				/* Do it here rather than reiterating again the group in case no member is up. */
926
				if (!is_array($backupplan[$tier])) {
927
					$backupplan[$tier] = array();
928
				}
929
				$backupplan[$tier][] = $gwname;
930

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

    
976
			/* we do not really foreach the tiers as we stop after the first tier */
977
			foreach ($tiers as $tieridx => $tier) {
978
				/* process all gateways in this tier */
979
				foreach ($tier as $member) {
980
					/* determine interface gateway */
981
					if (isset($gateways_arr[$member])) {
982
						$gateway = $gateways_arr[$member];
983
						$int = $gateway['interface'];
984
						$gatewayip = "";
985
						if (is_ipaddr($gateway['gateway'])) {
986
							$gatewayip = $gateway['gateway'];
987
						} else if (!empty($int)) {
988
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
989
						}
990

    
991
						if (!empty($int)) {
992
							$gateway_groups_array[$group['name']]['ipprotocol'] = $gateway['ipprotocol'];
993
							if (is_ipaddr($gatewayip)) {
994
								$groupmember = array();
995
								$groupmember['int'] = $int;
996
								$groupmember['gwip'] = $gatewayip;
997
								$groupmember['weight'] = isset($gateway['weight']) ? $gateway['weight'] : 1;
998
								if (is_array($gwvip_arr[$group['name']])&& !empty($gwvip_arr[$group['name']][$member])) {
999
									$groupmember['vip'] = $gwvip_arr[$group['name']][$member];
1000
								}
1001
								$gateway_groups_array[$group['name']][] = $groupmember;
1002
							}
1003
						}
1004
					}
1005
				}
1006
				/* we should have the 1st available tier now, exit stage left */
1007
				if (count($gateway_groups_array[$group['name']]) > 0) {
1008
					break;
1009
				} else {
1010
					log_error("GATEWAYS: Group {$group['name']} did not have any gateways up on tier {$tieridx}!");
1011
				}
1012
			}
1013
		}
1014
	}
1015

    
1016
	return ($gateway_groups_array);
1017
}
1018

    
1019
/* Update DHCP WAN Interface ip address in gateway group item */
1020
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
1021
	global $config, $g;
1022
	foreach ($config['gateways']['gateway_item'] as & $gw) {
1023
		if ($gw['interface'] == $interface) {
1024
			$current_gw = get_interface_gateway($interface);
1025
			if ($gw['gateway'] <> $current_gw) {
1026
				$gw['gateway'] = $current_gw;
1027
				$changed = true;
1028
			}
1029
		}
1030
	}
1031
	if ($changed && $current_gw) {
1032
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interfac, $current_gw));
1033
	}
1034
}
1035

    
1036
function lookup_gateway_ip_by_name($name, $disabled = false) {
1037

    
1038
	$gateways_arr = return_gateways_array($disabled, true);
1039
	foreach ($gateways_arr as $gname => $gw) {
1040
		if ($gw['name'] === $name || $gname === $name) {
1041
			return $gw['gateway'];
1042
		}
1043
	}
1044

    
1045
	return false;
1046
}
1047

    
1048
function lookup_gateway_monitor_ip_by_name($name) {
1049

    
1050
	$gateways_arr = return_gateways_array(false, true);
1051
	if (!empty($gateways_arr[$name])) {
1052
		$gateway = $gateways_arr[$name];
1053
		if (!is_ipaddr($gateway['monitor'])) {
1054
			return $gateway['gateway'];
1055
		}
1056

    
1057
		return $gateway['monitor'];
1058
	}
1059

    
1060
	return (false);
1061
}
1062

    
1063
function lookup_gateway_interface_by_name($name) {
1064

    
1065
	$gateways_arr = return_gateways_array(false, true);
1066
	if (!empty($gateways_arr[$name])) {
1067
		$interfacegw = $gateways_arr[$name]['friendlyiface'];
1068
		return ($interfacegw);
1069
	}
1070

    
1071
	return (false);
1072
}
1073

    
1074
function get_interface_gateway($interface, &$dynamic = false) {
1075
	global $config, $g;
1076

    
1077
	if (substr($interface, 0, 4) == '_vip') {
1078
		$interface = get_configured_carp_interface_list($interface, 'inet', 'iface');
1079
	}
1080

    
1081
	$gw = NULL;
1082
	$gwcfg = $config['interfaces'][$interface];
1083
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
1084
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1085
			if (($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
1086
				$gw = $gateway['gateway'];
1087
				break;
1088
			}
1089
		}
1090
	}
1091

    
1092
	// for dynamic interfaces we handle them through the $interface_router file.
1093
	if (($gw == NULL || !is_ipaddrv4($gw)) && !is_ipaddrv4($gwcfg['ipaddr'])) {
1094
		$realif = get_real_interface($interface);
1095
		if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1096
			$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
1097
			$dynamic = true;
1098
		}
1099
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw")) {
1100
			$dynamic = "default";
1101
		}
1102

    
1103
	}
1104

    
1105
	/* return gateway */
1106
	return ($gw);
1107
}
1108

    
1109
function get_interface_gateway_v6($interface, &$dynamic = false) {
1110
	global $config, $g;
1111

    
1112
	if (substr($interface, 0, 4) == '_vip') {
1113
		$interface = get_configured_carp_interface_list($interface, 'inet6', 'iface');
1114
	}
1115

    
1116
	$gw = NULL;
1117
	$gwcfg = $config['interfaces'][$interface];
1118
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
1119
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1120
			if (($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
1121
				$gw = $gateway['gateway'];
1122
				break;
1123
			}
1124
		}
1125
	}
1126

    
1127
	// for dynamic interfaces we handle them through the $interface_router file.
1128
	if (($gw == NULL || !is_ipaddrv6($gw)) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
1129
		$realif = get_real_interface($interface);
1130
		if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
1131
			$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
1132
			$dynamic = true;
1133
		}
1134
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6")) {
1135
			$dynamic = "default";
1136
		}
1137
	}
1138
	/* return gateway */
1139
	return ($gw);
1140
}
1141

    
1142
/* Check a IP address against a gateway IP or name
1143
 * to verify it's address family */
1144
function validate_address_family($ipaddr, $gwname, $disabled = false) {
1145
	$v4ip = false;
1146
	$v6ip = false;
1147
	$v4gw = false;
1148
	$v6gw = false;
1149

    
1150
	if (is_ipaddrv4($ipaddr)) {
1151
		$v4ip = true;
1152
	}
1153
	if (is_ipaddrv6($ipaddr)) {
1154
		$v6ip = true;
1155
	}
1156
	if (is_ipaddrv4($gwname)) {
1157
		$v4gw = true;
1158
	}
1159
	if (is_ipaddrv6($gwname)) {
1160
		$v6gw = true;
1161
	}
1162

    
1163
	if ($v4ip && $v4gw) {
1164
		return true;
1165
	}
1166
	if ($v6ip && $v6gw) {
1167
		return true;
1168
	}
1169

    
1170
	/* still no match, carry on, lookup gateways */
1171
	if (is_ipaddrv4(lookup_gateway_ip_by_name($gwname, $disabled))) {
1172
		$v4gw = true;
1173
	}
1174
	if (is_ipaddrv6(lookup_gateway_ip_by_name($gwname, $disabled))) {
1175
		$v6gw = true;
1176
	}
1177

    
1178
	$gw_array = return_gateways_array();
1179
	if (is_array($gw_array[$gwname])) {
1180
		switch ($gw_array[$gwname]['ipprotocol']) {
1181
			case "inet":
1182
				$v4gw = true;
1183
				break;
1184
			case "inet6":
1185
				$v6gw = true;
1186
				break;
1187
		}
1188
	}
1189

    
1190
	if ($v4ip && $v4gw) {
1191
		return true;
1192
	}
1193
	if ($v6ip && $v6gw) {
1194
		return true;
1195
	}
1196

    
1197
	return false;
1198
}
1199

    
1200
/* check if a interface is part of a gateway group */
1201
function interface_gateway_group_member($interface) {
1202
	global $config;
1203

    
1204
	if (is_array($config['gateways']['gateway_group'])) {
1205
		$groups = $config['gateways']['gateway_group'];
1206
	} else {
1207
		return false;
1208
	}
1209

    
1210
	$gateways_arr = return_gateways_array(false, true);
1211
	foreach ($groups as $group) {
1212
		if (is_array($group['item'])) {
1213
			foreach ($group['item'] as $item) {
1214
				$elements = explode("|", $item);
1215
				$gwname = $elements[0];
1216
				if ($interface == $gateways_arr[$gwname]['interface']) {
1217
					unset($gateways_arr);
1218
					return true;
1219
				}
1220
			}
1221
		}
1222
	}
1223
	unset($gateways_arr);
1224

    
1225
	return false;
1226
}
1227

    
1228
function gateway_is_gwgroup_member($name) {
1229
	global $config;
1230

    
1231
	if (is_array($config['gateways']['gateway_group'])) {
1232
		$groups = $config['gateways']['gateway_group'];
1233
	} else {
1234
		return false;
1235
	}
1236

    
1237
	$members = array();
1238
	foreach ($groups as $group) {
1239
		if (is_array($group['item'])) {
1240
			foreach ($group['item'] as $item) {
1241
				$elements = explode("|", $item);
1242
				$gwname = $elements[0];
1243
				if ($name == $elements[0]) {
1244
					$members[] = $group['name'];
1245
				}
1246
			}
1247
		}
1248
	}
1249

    
1250
	return $members;
1251
}
1252
?>
(25-25/68)