Project

General

Profile

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

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

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

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

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

    
28
	pfSense_BUILDER_BINARIES:	/usr/bin/killall	/sbin/route	/usr/local/sbin/apinger
29
	pfSense_MODULE:	routing
30

    
31
 */
32

    
33
/*
34
 * Creates monitoring configuration file and
35
 * adds apropriate static routes.
36
 */
37
function setup_gateways_monitor() {
38
	global $config, $g;
39

    
40
	$gateways_arr = return_gateways_array();
41
	if (!is_array($gateways_arr)) {
42
		log_error("No gateways to monitor. Apinger will not be run.");
43
		killbypid("{$g['varrun_path']}/apinger.pid");
44
		@unlink("{$g['tmp_path']}/apinger.status");
45
		return;
46
	}
47

    
48
	/* Default settings. Probably should move to globals.inc? */
49
	$a_settings = array();
50
	$a_settings['latencylow'] = "200";
51
	$a_settings['latencyhigh'] = "500";
52
	$a_settings['losslow'] = "10";
53
	$a_settings['losshigh'] = "20";
54

    
55
	$fd = fopen("{$g['varetc_path']}/apinger.conf", "w");
56
	$apingerconfig = <<<EOD
57

    
58
# pfSense apinger configuration file. Automatically Generated!
59

    
60
## User and group the pinger should run as
61
user "root"
62
group "wheel"
63

    
64
## Mailer to use (default: "/usr/lib/sendmail -t")
65
#mailer "/var/qmail/bin/qmail-inject" 
66

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

    
70
## Format of timestamp (%s macro) (default: "%b %d %H:%M:%S")
71
#timestamp_format "%Y%m%d%H%M%S"
72

    
73
status {
74
	## File where the status information whould be written to
75
	file "{$g['tmp_path']}/apinger.status"
76
	## Interval between file updates
77
	## when 0 or not set, file is written only when SIGUSR1 is received
78
	interval 5s
79
}
80

    
81
########################################
82
# RRDTool status gathering configuration
83
# Interval between RRD updates
84
rrd interval 60s;
85

    
86
## These parameters can be overriden in a specific alarm configuration
87
alarm default { 
88
	command on "/usr/local/sbin/pfSctl -c 'filter reload'"
89
	command off "/usr/local/sbin/pfSctl -c 'filter reload'"
90
	combine 10s
91
}
92

    
93
## "Down" alarm definition. 
94
## This alarm will be fired when target doesn't respond for 30 seconds.
95
alarm down "down" {
96
	time 10s
97
}
98

    
99
## "Delay" alarm definition. 
100
## This alarm will be fired when responses are delayed more than 200ms
101
## it will be canceled, when the delay drops below 100ms
102
alarm delay "delay" {
103
	delay_low {$a_settings['latencylow']}ms
104
	delay_high {$a_settings['latencyhigh']}ms
105
}
106

    
107
## "Loss" alarm definition. 
108
## This alarm will be fired when packet loss goes over 20%
109
## it will be canceled, when the loss drops below 10%
110
alarm loss "loss" {
111
	percent_low {$a_settings['losslow']}
112
	percent_high {$a_settings['losshigh']}
113
}
114

    
115
target default {
116
	## How often the probe should be sent	
117
	interval 1s
118
	
119
	## How many replies should be used to compute average delay 
120
	## for controlling "delay" alarms
121
	avg_delay_samples 10
122
	
123
	## How many probes should be used to compute average loss
124
	avg_loss_samples 50
125

    
126
	## The delay (in samples) after which loss is computed
127
	## without this delays larger than interval would be treated as loss
128
	avg_loss_delay_samples 20
129

    
130
	## Names of the alarms that may be generated for the target
131
	alarms "down","delay","loss"
132

    
133
	## Location of the RRD
134
	#rrd file "{$g['vardb_path']}/rrd/apinger-%t.rrd"
135
}
136

    
137
EOD;
138

    
139
	foreach($gateways_arr as $name => $gateway) {
140
		/* Do not monitor if such was requested */
141
		if (isset($gateway['monitor_disable']))
142
			continue;
143
		if (empty($gateway['monitor']) || !is_ipaddr($gateway['monitor'])) {
144
			if (is_ipaddr($gateway['gateway']))
145
				$gateway['monitor'] = $gateway['gateway'];
146
			else /* No chance to get an ip to monitor skip target. */
147
				continue;
148
		}
149

    
150
		/* Interface ip is needed since apinger will bind a socket to it. */
151
		if (is_ipaddrv4($gateway['gateway'])) {
152
			$gwifip = find_interface_ip($gateway['interface'], true);
153
		}
154
		if (is_ipaddrv6($gateway['gateway'])) {
155
			/* link locals really need a different src ip */
156
			if(preg_match("/fe80::/i", $gateway['gateway'])) {
157
				$linklocal = explode("%", find_interface_ipv6_ll($gateway['interface'], true));
158
				$gwifip = $linklocal[0];
159
				$ifscope = "%". $linklocal[1];
160
			} else {
161
				$gwifip = find_interface_ipv6($gateway['interface'], true);
162
			}
163
		}
164
		if (!is_ipaddr($gwifip))
165
			continue; //Skip this target
166

    
167
		$apingercfg = "target \"{$gateway['monitor']}\" {\n";
168
		$apingercfg .= "	description \"{$name}\"\n";
169
		$apingercfg .= "	srcip \"{$gwifip}\"\n";
170
		if (!empty($gateway['interval']) && intval($gateway['interval']) > 1)
171
			$apingercfg .= "	interval " . intval($gateway['interval']) . "s\n";
172
		$alarms = "";
173
		$alarmscfg = "";
174
		$override = false;
175
		if (!empty($gateway['lowloss'])) {
176
			$alarmscfg .= "alarm loss \"{$name}loss\" {\n";
177
			$alarmscfg .= "\tpercent_low {$gateway['losslow']}\n";
178
       			$alarmscfg .= "\tpercent_high {$gateway['losshigh']}\n";
179
			$alarmscfg .= "}\n";
180
			$alarms .= "\"{$name}loss\"";
181
			$override = true;
182
		} else {
183
			if ($override == true)
184
				$alarms .= ",";
185
			$alarms .= "\"loss\"";
186
			$override = true;
187
		}
188
		if (!empty($gateway['latencylow'])) {
189
			$alarmscfg .= "alarm delay \"{$name}delay\" {\n";
190
			$alarmscfg .= "\tdelay_low {$gateway['latencylow']}ms\n";
191
			$alarmscfg .= "\tdelay_high {$gateway['latencyhigh']}ms\n";
192
			$alarmscfg .= "}\n";
193
			if ($override == true)
194
				$alarms .= ",";
195
			$alarms .= "\"{$name}delay\"";
196
			$override = true;
197
		} else {
198
			if ($override == true)
199
				$alarms .= ",";
200
			$alarms .= "\"delay\"";
201
			$override = true;
202
		}
203
		if (!empty($gateway['down'])) {
204
			$alarmscfg .= "alarm down \"{$name}down\" {\n";
205
			$alarmscfg .= "\ttime {$gateway['down']}s\n";
206
			$alarmscfg .= "}\n";
207
			if ($override == true)
208
				$alarms .= ",";
209
			$alarms .= "\"{$name}down\"";
210
			$override = true;
211
		} else {
212
			if ($override == true)
213
				$alarms .= ",";
214
			$alarms .= "\"down\"";
215
			$override = true;
216
		}
217
		if ($override == true)
218
			$apingercfg .= "\talarms override {$alarms};\n";
219

    
220
		$apingercfg .= "	rrd file \"{$g['vardb_path']}/rrd/{$gateway['name']}-quality.rrd\"\n";
221
		$apingercfg .= "}\n";
222
		$apingercfg .= "\n";
223
		/*
224
		 * If the gateway is the same as the monitor we do not add a
225
		 * route as this will break the routing table.
226
		 * Add static routes for each gateway with their monitor IP
227
		 * not strictly necessary but is a added level of protection.
228
		 */
229
		if (is_ipaddr($gateway['gateway']) && $gateway['monitor'] != $gateway['gateway']) {
230
			log_error(sprintf(gettext('Removing static route for monitor %1$s and adding a new route through %2$s'), $gateway['monitor'], $gateway['gateway']));
231
			mwexec("/sbin/route change -host " . escapeshellarg($gateway['monitor']) .
232
				" " . escapeshellarg($gateway['gateway']), true);
233
		}
234

    
235
		$apingerconfig .= $alarmscfg;
236
		$apingerconfig .= $apingercfg;
237
	}
238
	fwrite($fd, $apingerconfig);
239
	fclose($fd);
240

    
241
	killbypid("{$g['varrun_path']}/apinger.pid");
242
	if (is_dir("{$g['tmp_path']}"))
243
		chmod("{$g['tmp_path']}", 01777);
244
	if (!is_dir("{$g['vardb_path']}/rrd"))
245
		mkdir("{$g['vardb_path']}/rrd", 0775);
246

    
247
	@chown("{$g['vardb_path']}/rrd", "nobody");
248

    
249
	/* start a new apinger process */
250
	@unlink("{$g['tmp_path']}/apinger.status");
251
	sleep(1);
252
	mwexec_bg("/usr/local/sbin/apinger -c {$g['varetc_path']}/apinger.conf");
253

    
254
	return 0;
255
}
256

    
257
/* return the status of the apinger targets as a array */
258
function return_gateways_status($byname = false) {
259
	global $config, $g;
260

    
261
	$apingerstatus = array();
262
	if (file_exists("{$g['tmp_path']}/apinger.status")) {
263
		$apingerstatus = file("{$g['tmp_path']}/apinger.status");
264
	}
265

    
266
	$status = array();
267
	foreach($apingerstatus as $line) {
268
		$info = explode("|", $line);
269
		if ($byname == false)
270
			$target = $info[0];
271
		else
272
			$target = $info[2];
273
		$status[$target]['monitorip'] = $info[0];
274
		$status[$target]['srcip'] = $info[1];
275
		$status[$target]['name'] = $info[2];
276
		$status[$target]['lastcheck'] = $info[5] ? date('r', $info[5]) : date('r');
277
		$status[$target]['delay'] = empty($info[6]) ? 0 : $info[6];
278
		$status[$target]['loss'] = empty($info[7]) ? "0.0%" : $info[7] . "";
279
		$status[$target]['status'] = trim($info[8]);
280
	}
281

    
282
	/* tack on any gateways that have monitoring disabled */
283
	$gateways_arr = return_gateways_array();
284
	foreach($gateways_arr as $gwitem) {
285
		if(isset($gwitem['monitor_disable'])) {
286
			if(!is_ipaddr($gwitem['monitorip'])) {
287
				$realif = $gwitem['interface'];
288
				$tgtip = get_interface_gateway($realif);
289
				$srcip = find_interface_ip($realif);
290
			} else {
291
				$tgtip = $gwitem['monitorip'];
292
				$srcip = find_interface_ip($realif);
293
			}
294
			if($byname == true)
295
				$target = $gwitem['name'];
296
			else
297
				$target = $tgtip;
298

    
299
			$status[$target]['monitorip'] = $tgtip;
300
			$status[$target]['srcip'] = $srcip;
301
			$status[$target]['name'] = $gwitem['name'];
302
			$status[$target]['lastcheck'] = date('r');
303
			$status[$target]['delay'] = "0.0ms";
304
			$status[$target]['loss'] = "0.0%";
305
			$status[$target]['status'] = "none";
306
		}
307
	}
308
	return($status);
309
}
310

    
311
/* Return all configured gateways on the system */
312
function return_gateways_array($disabled = false) {
313
	global $config, $g;
314

    
315
	$gateways_arr = array();
316

    
317
	$i = 0;
318
	/* Process/add all the configured gateways. */
319
	if (is_array($config['gateways']['gateway_item'])) {
320
		foreach($config['gateways']['gateway_item'] as $gateway) {
321
			if(empty($gateway['gateway']) || preg_match("/dynamic/", $gateway['gateway'])) {
322
				$gateway['gateway'] = get_interface_gateway($gateway['interface']);
323
				if(preg_match("/dynamic/", $gateway['gateway'])) {
324
					$dynstr = $gateway['gateway'];
325
				}
326
				/* no IP address found, set to dynamic */
327
				if(! is_ipaddr($gateway['gateway'])) {
328
					$gateway['gateway'] = "{$dynstr}";
329
				}
330
				$gateway['dynamic'] = true;
331
			}
332
			if(is_ipaddrv4($gateway['gateway']))
333
				$gateway['ipprotocol'] = "inet";
334
			if(is_ipaddrv6($gateway['gateway']))
335
				$gateway['ipprotocol'] = "inet6";
336
			if (isset($gateway['monitor_disable']))
337
				$gateway['monitor_disable'] = true;
338
			else if (empty($gateway['monitor']))
339
				$gateway['monitor'] = $gateway['gateway'];
340

    
341
			$gateway['friendlyiface'] = $gateway['interface'];
342
			$gateway['interface'] = get_real_interface($gateway['interface']);
343
			/* FIXME: Should this be enabled.
344
			 * Some interface like wan might be default but have no info recorded 
345
			 * the config.
346
			if ($gateway['friendlyiface'] == "wan" && !isset($gateway['defaultgw'])) {
347
				if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgw"))
348
					$gateway['defaultgw'] = true;
349
			}
350
			 */
351
			/* include the gateway index as the attribute */
352
			$gateway['attribute'] = $i;
353

    
354
			$gateways_arr[$gateway['name']] = $gateway;
355
			$i++;
356
		}
357
	} 
358

    
359
	/* Loop through all interfaces with a gateway and add it to a array */
360
	if ($disabled == false)
361
		$iflist = get_configured_interface_with_descr();
362
	else
363
		$iflist = get_configured_interface_with_descr(false, true);
364

    
365
	/* Process/add dynamic v4 gateways. */
366
	foreach($iflist as $ifname => $friendly ) {
367
		if(! interface_has_gateway($ifname))
368
			continue;
369

    
370
		if (empty($config['interfaces'][$ifname]))
371
			continue;
372

    
373
		$ifcfg = &$config['interfaces'][$ifname];
374
		if(!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr']))
375
			continue;
376

    
377
		$gateway = array();
378
		$gateway['dynamic'] = false;
379
		$gateway['ipprotocol'] = "inet";
380
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
381
		$gateway['interface'] = get_real_interface($ifname);
382
		$gateway['friendlyiface'] = $ifname;
383
		$gateway['name'] = $friendly;
384
		$gateway['attribute'] = "system";
385
	
386
		if ($gateway['dynamic'] === "default") {
387
			$gateway['defaultgw'] = true;
388
			$gateway['dynamic'] = true;
389
		}
390
		/* Loopback dummy for dynamic interfaces without a IP */
391
		if (!is_ipaddrv4($gateway['gateway']) && $gateway['dynamic'] == true)
392
			$gateway['gateway'] = "dynamic";
393

    
394
		/* automatically skip known static and dynamic gateways we have a array entry for */
395
		foreach($gateways_arr as $gateway_item) {
396
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name'])&& ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
397
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
398
					continue 2;
399
		}
400

    
401
		if (is_ipaddrv4($gateway['gateway']))
402
			$gateway['monitor'] = $gateway['gateway'];
403

    
404
		$gateway['descr'] = "Interface {$friendly} Dynamic Gateway";
405
		$gateways_arr[$gateway['name']] = $gateway;
406
	}
407

    
408
	/* Process/add dynamic v6 gateways. */
409
	foreach($iflist as $ifname => $friendly ) {
410
		if(! interface_has_gatewayv6($ifname))
411
			continue;
412

    
413
		if (empty($config['interfaces'][$ifname]))
414
			continue;
415

    
416
		$ifcfg = &$config['interfaces'][$ifname];
417
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
418
			continue;
419

    
420
		$gateway = array();
421
		$gateway['dynamic'] = false;
422
		$gateway['ipprotocol'] = "inet6";
423
		$gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
424
		$gateway['interface'] = get_real_interface($ifname);
425
		$gateway['friendlyiface'] = $ifname;
426
		$gateway['name'] = "{$friendly}_v6";
427
		$gateway['attribute'] = "system";
428
	
429
		if ($gateway['dynamic'] === "default") {
430
			$gateway['defaultgw'] = true;
431
			$gateway['dynamic'] = true;
432
		}
433

    
434
		/* Loopback dummy for dynamic interfaces without a IP */
435
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
436
			$gateway['gateway'] = "dynamic6";
437

    
438
		/* automatically skip known static and dynamic gateways we have a array entry for */
439
		foreach($gateways_arr as $gateway_item) {
440
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
441
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
442
					continue 2;
443
		}
444

    
445
		if (is_ipaddrv6($gateway['gateway']))
446
			$gateway['monitor'] = $gateway['gateway'];
447

    
448
		$gateway['descr'] = "Interface {$friendly} Dynamic Gateway";
449
		$gateways_arr[$gateway['name']] = $gateway;
450
	}
451
	return($gateways_arr);
452
}
453

    
454
/*
455
 * Return an array with all gateway groups with name as key
456
 * All gateway groups will be processed before returning the array.
457
 */
458
function return_gateway_groups_array() {
459
	global $config, $g;
460

    
461
	/* fetch the current gateways status */
462
	$gateways_status = return_gateways_status(true);
463
	$gateways_arr = return_gateways_array();
464
	$gateway_groups_array = array();
465

    
466
	if (isset($config['system']['gw_switch_default'])) {
467
		/* 
468
		 * NOTE: The code below is meant to replace the default gateway when it goes down.
469
		 *	This facilitates services running on pfSense itself and are not handled by a PBR to continue working.
470
		 */
471
		$upgw = "";
472
		$dfltgwdown = false;
473
		$dfltgwfound = false;
474
		foreach ($gateways_arr as $gwname => $gwsttng) {
475
			if (isset($gwsttng['defaultgw'])) {
476
				$dfltgwfound = true;
477
				$dfltgwname = $gwname;
478
				if (!isset($gwsttng['monitor_disable']) && stristr($gateways_status[$gwname]['status'], "down"))
479
					$dfltgwdown = true;
480
			}
481
			/* Keep a record of the last up gateway */
482
			/* XXX: Blacklist lan for now since it might cause issues to those who have a gateway set for it */
483
			if (empty($upgw) && (isset($gwsttng['monitor_disable']) || !stristr($gateways_status[$gwname]['status'], "down")) && $gwsttng[$gwname]['friendlyiface'] != "lan")
484
				$upgw = $gwname;
485
			if ($dfltgwdown == true && !empty($upgw))
486
				break;
487
		}
488
		if ($dfltgwfound == false) {
489
			$gwname = convert_friendly_interface_to_friendly_descr("wan");
490
			if (!empty($gateways_status[$gwname]) && stristr($gateways_status[$gwname]['status'], "down"))
491
				$dfltgwdown = true;
492
		}
493
		if ($dfltgwdown == true && !empty($upgw)) {
494
			if (preg_match("/dynamic", $gateways_arr[$upgw]['gateway']))
495
				$gateways_arr[$upgw]['gateway'] = get_interface_gateway($gateways_arr[$upgw]['friendlyiface']);
496
			if (is_ipaddr($gateways_arr[$upgw]['gateway'])) {
497
				log_error("Default gateway down setting {$upgw} as default!");
498
				mwexec("/sbin/route change -inet default {$gateways_arr[$upgw]['gateway']}");
499
			}
500
		} else {
501
			$defaultgw = trim(`/sbin/route -n get -inet default | /usr/bin/grep gateway | /usr/bin/sed 's/gateway://g'`, " \n");
502
			if ($defaultgw != $gateways_arr[$dfltgwname]['gateway'])
503
				mwexec("/sbin/route change -inet default {$gateways_arr[$dfltgwname]['gateway']}");
504
		}
505
				
506
		unset($upgw, $dfltgwfound, $dfltgwdown, $gwname, $gwsttng);
507
	}
508

    
509
	if (is_array($config['gateways']['gateway_group'])) {
510
		foreach($config['gateways']['gateway_group'] as $group) {
511
			/* create array with group gateways members seperated by tier */
512
			$tiers = array();
513
			$backupplan = array();
514
			foreach($group['item'] as $item) {
515
				$itemsplit = explode("|", $item);
516
				$tier = $itemsplit[1];
517
				$gwname = $itemsplit[0];
518

    
519
				/* Do it here rather than reiterating again the group in case no member is up. */
520
				$backupplan[$tier][] = $gwname;
521

    
522
				/* check if the gateway is available before adding it to the array */
523
				if (!empty($gateways_status[$gwname])) {
524
					$status = $gateways_status[$gwname];
525
					$gwdown = false;
526
					if (stristr($status['status'], "down")) {
527
						$msg = sprintf(gettext("MONITOR: %s is down, removing from routing group"), $gwname);
528
						$gwdown = true;
529
					} else if (stristr($status['status'], "loss") && strstr($group['trigger'], "loss")) {
530
						/* packet loss */
531
						$msg = sprintf(gettext("MONITOR: %s has packet loss, removing from routing group"), $gwname);
532
						$gwdown = true;
533
					} else if (stristr($status['status'], "delay") && strstr($group['trigger'] , "latency")) {
534
						/* high latency */
535
						$msg = sprintf(gettext("MONITOR: %s has high latency, removing from routing group"), $gwname);
536
						$gwdown = true;
537
					}
538
					if ($gwdown == true) {
539
						log_error($msg);
540
						notify_via_growl($msg);
541
						notify_via_smtp($msg);
542
					} else
543
						/* Online add member */
544
						$tiers[$tier][] = $gwname;
545
				} else if (isset($gateways_arr[$gwname]['monitor_disable']))
546
					$tiers[$tier][] = $gwname;
547
			}
548
			$tiers_count = count($tiers);
549
			if($tiers_count == 0) {
550
				/* Oh dear, we have no members! Engage Plan B */
551
				if (!$g['booting']) {
552
					$msg = gettext("Gateways status could not be determined, considering all as up/active.");
553
					log_error($msg);
554
					notify_via_growl($msg);
555
					notify_via_smtp($msg);
556
				}
557
				$tiers = $backupplan;
558
			}
559
			/* sort the tiers array by the tier key */
560
			ksort($tiers);
561

    
562
			/* we do not really foreach the tiers as we stop after the first tier */
563
			foreach($tiers as $tier) {
564
				/* process all gateways in this tier */
565
				foreach($tier as $member) {
566
					/* determine interface gateway */
567
					if (isset($gateways_arr[$member])) {
568
						$gateway = $gateways_arr[$member];
569
						$int = $gateway['interface'];
570
						$gatewayip = "";
571
						if(is_ipaddr($gateway['gateway'])) 
572
							$gatewayip = $gateway['gateway'];
573
						else if ($int <> "")
574
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
575
					
576
						if (($int <> "") && is_ipaddr($gatewayip)) {
577
							$groupmember = array();
578
							$groupmember['int']  = $int;
579
							$groupmember['gwip']  = $gatewayip;
580
							$groupmember['weight']  = isset($gateway['weight']) ? $gateway['weight'] : 1;
581
							$gateway_groups_array[$group['name']][] = $groupmember;
582
						}
583
					}
584
				}
585
				/* we should have the 1st available tier now, exit stage left */
586
				break;
587
			}
588
		}
589
	}
590
	return ($gateway_groups_array);
591
}
592

    
593
/* Update DHCP WAN Interface ip address in gateway group item */
594
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
595
	global $config, $g;
596
	foreach($config['gateways']['gateway_item'] as & $gw) {	
597
		if($gw['interface'] == $interface) {
598
			$current_gw = get_interface_gateway($interface);
599
			if($gw['gateway'] <> $current_gw) {
600
				$gw['gateway'] = $current_gw;
601
				$changed = true;
602
			}
603
		}
604
	}
605
	if($changed && $current_gw)
606
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interfac, $current_gw));
607
}
608

    
609
function lookup_gateway_ip_by_name($name) {
610

    
611
	$gateways_arr = return_gateways_array();
612
        foreach ($gateways_arr as $gname => $gw) {
613
                if ($gw['name'] == $name || $gname == $name)
614
                        return $gw['gateway'];
615
        }
616

    
617
	return false;
618
}
619

    
620
function lookup_gateway_monitor_ip_by_name($name) {
621

    
622
        $gateways_arr = return_gateways_array();
623
	if (!empty($gateways_arr[$name])) {
624
		$gateway = $gateways_arr[$name];
625
		if(!is_ipaddr($gateway['monitor']))
626
			return $gateway['gateway'];
627

    
628
		return $gateway['monitor'];
629
        }
630

    
631
        return (false);
632
}
633

    
634
function lookup_gateway_interface_by_name($name) {
635

    
636
        $gateways_arr = return_gateways_array();
637
	if (!empty($gateways_arr[$name])) {
638
		$interfacegw = $gateway['interface'];
639
		return ($interfacegw);
640
        }
641

    
642
        return (false);
643
}
644

    
645
function get_interface_gateway($interface, &$dynamic = false) {
646
	global $config, $g;
647

    
648
	$gw = NULL;
649

    
650
	$gwcfg = $config['interfaces'][$interface];
651
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
652
		foreach($config['gateways']['gateway_item'] as $gateway) {
653
			if(($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
654
				$gw = $gateway['gateway'];
655
				break;
656
			}
657
		}
658
	}
659

    
660
	// for dynamic interfaces we handle them through the $interface_router file.
661
	if (!is_ipaddrv4($gw) && !is_ipaddrv4($gwcfg['ipaddr'])) {
662
		$realif = get_real_interface($interface);
663
		if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
664
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
665
			$dynamic = true;
666
		}
667
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw"))
668
			$dynamic = "default";
669
			
670
	}
671

    
672
	/* return gateway */
673
	return ($gw);
674
}
675

    
676
function get_interface_gateway_v6($interface, &$dynamic = false) {
677
	global $config, $g;
678

    
679
	$gw = NULL;
680
	$gwcfg = $config['interfaces'][$interface];
681
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
682
		foreach($config['gateways']['gateway_item'] as $gateway) {
683
			if(($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
684
				$gw = $gateway['gateway'];
685
				break;
686
			}
687
		}
688
	}
689

    
690
	// for dynamic interfaces we handle them through the $interface_router file.
691
	if (!is_ipaddrv6($gw) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
692
			$realif = get_real_interface($interface);
693
			if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
694
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
695
				$dynamic = true;
696
			}
697
			if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6"))
698
				$dynamic = "default";
699
			
700
	}
701
	/* return gateway */
702
	return ($gw);
703
}
704

    
705
/* Check a IP address against a gateway IP or name
706
 * to verify it's address family */
707
function validate_address_family($ipaddr, $gwname) {
708
	$v4ip = false;
709
	$v6ip = false;
710
	$v4gw = false;
711
	$v6gw = false;
712

    
713
	if(is_ipaddrv4($ipaddr))
714
		$v4ip = true;
715
	if(is_ipaddrv6($ipaddr))
716
		$v6ip = true;
717
	if(is_ipaddrv4($gwname))
718
		$v4gw = true;
719
	if(is_ipaddrv6($gwname))
720
		$v6gw = true;
721

    
722
	if($v4ip && $v4gw)
723
		return true;
724
	if($v6ip && $v6gw)
725
		return true;
726

    
727
	/* still no match, carry on, lookup gateways */
728
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
729
		$v4gw = true;
730
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
731
		$v6gw = true;
732
	/* are they dynamic */
733
	switch($gwname) {
734
		case "dynamic":
735
			$v4gw = true;
736
			break;
737
		case "dynamic6":
738
			$v6gw = true;
739
			break;
740
	}
741

    
742
	if($v4ip && $v4gw)
743
		return true;
744
	if($v6ip && $v6gw)
745
		return true;
746
	
747
	return false;
748
}
749

    
750

    
751
?>
(25-25/64)