Project

General

Profile

Download (24.2 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
		/* XXX Add stf and friends in the future ? */
425
		switch($ifcfg['ipaddrv6']) {
426
			case "6rd":
427
				$gateway['interface'] = "srd0";
428
				$gateway['dynamic'] = "default";
429
				$gateway['gateway'] = "::1";
430
				break;
431
			default:
432
				$gateway['interface'] = get_real_interface($ifname);
433
				break;
434
		}
435
		$gateway['friendlyiface'] = $ifname;
436
		$gateway['name'] = "{$friendly}_v6";
437
		$gateway['attribute'] = "system";
438
	
439
		if ($gateway['dynamic'] === "default") {
440
			$gateway['defaultgw'] = true;
441
			$gateway['dynamic'] = true;
442
		}
443

    
444
		/* Loopback dummy for dynamic interfaces without a IP */
445
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
446
			$gateway['gateway'] = "dynamic6";
447

    
448
		/* automatically skip known static and dynamic gateways we have a array entry for */
449
		foreach($gateways_arr as $gateway_item) {
450
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
451
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
452
					continue 2;
453
		}
454

    
455
		if (is_ipaddrv6($gateway['gateway']))
456
			$gateway['monitor'] = $gateway['gateway'];
457

    
458
		$gateway['descr'] = "Interface {$friendly} Dynamic Gateway";
459
		$gateways_arr[$gateway['name']] = $gateway;
460
	}
461
	return($gateways_arr);
462
}
463

    
464
/*
465
 * Return an array with all gateway groups with name as key
466
 * All gateway groups will be processed before returning the array.
467
 */
468
function return_gateway_groups_array() {
469
	global $config, $g;
470

    
471
	/* fetch the current gateways status */
472
	$gateways_status = return_gateways_status(true);
473
	$gateways_arr = return_gateways_array();
474
	$gateway_groups_array = array();
475

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

    
519
	if (is_array($config['gateways']['gateway_group'])) {
520
		foreach($config['gateways']['gateway_group'] as $group) {
521
			/* create array with group gateways members seperated by tier */
522
			$tiers = array();
523
			$backupplan = array();
524
			foreach($group['item'] as $item) {
525
				$itemsplit = explode("|", $item);
526
				$tier = $itemsplit[1];
527
				$gwname = $itemsplit[0];
528

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

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

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

    
603
/* Update DHCP WAN Interface ip address in gateway group item */
604
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
605
	global $config, $g;
606
	foreach($config['gateways']['gateway_item'] as & $gw) {	
607
		if($gw['interface'] == $interface) {
608
			$current_gw = get_interface_gateway($interface);
609
			if($gw['gateway'] <> $current_gw) {
610
				$gw['gateway'] = $current_gw;
611
				$changed = true;
612
			}
613
		}
614
	}
615
	if($changed && $current_gw)
616
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interfac, $current_gw));
617
}
618

    
619
function lookup_gateway_ip_by_name($name) {
620

    
621
	$gateways_arr = return_gateways_array();
622
        foreach ($gateways_arr as $gname => $gw) {
623
                if ($gw['name'] == $name || $gname == $name)
624
                        return $gw['gateway'];
625
        }
626

    
627
	return false;
628
}
629

    
630
function lookup_gateway_monitor_ip_by_name($name) {
631

    
632
        $gateways_arr = return_gateways_array();
633
	if (!empty($gateways_arr[$name])) {
634
		$gateway = $gateways_arr[$name];
635
		if(!is_ipaddr($gateway['monitor']))
636
			return $gateway['gateway'];
637

    
638
		return $gateway['monitor'];
639
        }
640

    
641
        return (false);
642
}
643

    
644
function lookup_gateway_interface_by_name($name) {
645

    
646
        $gateways_arr = return_gateways_array();
647
	if (!empty($gateways_arr[$name])) {
648
		$interfacegw = $gateway['interface'];
649
		return ($interfacegw);
650
        }
651

    
652
        return (false);
653
}
654

    
655
function get_interface_gateway($interface, &$dynamic = false) {
656
	global $config, $g;
657

    
658
	$gw = NULL;
659

    
660
	$gwcfg = $config['interfaces'][$interface];
661
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
662
		foreach($config['gateways']['gateway_item'] as $gateway) {
663
			if(($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
664
				$gw = $gateway['gateway'];
665
				break;
666
			}
667
		}
668
	}
669

    
670
	// for dynamic interfaces we handle them through the $interface_router file.
671
	if (!is_ipaddrv4($gw) && !is_ipaddrv4($gwcfg['ipaddr'])) {
672
		$realif = get_real_interface($interface);
673
		if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
674
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
675
			$dynamic = true;
676
		}
677
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw"))
678
			$dynamic = "default";
679
			
680
	}
681

    
682
	/* return gateway */
683
	return ($gw);
684
}
685

    
686
function get_interface_gateway_v6($interface, &$dynamic = false) {
687
	global $config, $g;
688

    
689
	$gw = NULL;
690
	$gwcfg = $config['interfaces'][$interface];
691
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
692
		foreach($config['gateways']['gateway_item'] as $gateway) {
693
			if(($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
694
				$gw = $gateway['gateway'];
695
				break;
696
			}
697
		}
698
	}
699

    
700
	// for dynamic interfaces we handle them through the $interface_router file.
701
	if (!is_ipaddrv6($gw) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
702
			$realif = get_real_interface($interface);
703
			if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
704
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
705
				$dynamic = true;
706
			}
707
			if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6"))
708
				$dynamic = "default";
709
			
710
	}
711
	/* return gateway */
712
	return ($gw);
713
}
714

    
715
/* Check a IP address against a gateway IP or name
716
 * to verify it's address family */
717
function validate_address_family($ipaddr, $gwname) {
718
	$v4ip = false;
719
	$v6ip = false;
720
	$v4gw = false;
721
	$v6gw = false;
722

    
723
	if(is_ipaddrv4($ipaddr))
724
		$v4ip = true;
725
	if(is_ipaddrv6($ipaddr))
726
		$v6ip = true;
727
	if(is_ipaddrv4($gwname))
728
		$v4gw = true;
729
	if(is_ipaddrv6($gwname))
730
		$v6gw = true;
731

    
732
	if($v4ip && $v4gw)
733
		return true;
734
	if($v6ip && $v6gw)
735
		return true;
736

    
737
	/* still no match, carry on, lookup gateways */
738
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
739
		$v4gw = true;
740
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
741
		$v6gw = true;
742
	/* are they dynamic */
743
	switch($gwname) {
744
		case "dynamic":
745
			$v4gw = true;
746
			break;
747
		case "dynamic6":
748
			$v6gw = true;
749
			break;
750
	}
751

    
752
	if($v4ip && $v4gw)
753
		return true;
754
	if($v6ip && $v6gw)
755
		return true;
756
	
757
	return false;
758
}
759

    
760

    
761
?>
(25-25/64)