Project

General

Profile

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

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

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

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

    
241
		$apingerconfig .= $alarmscfg;
242
		$apingerconfig .= $apingercfg;
243
	}
244
	fwrite($fd, $apingerconfig);
245
	fclose($fd);
246

    
247
	killbypid("{$g['varrun_path']}/apinger.pid");
248
	if (is_dir("{$g['tmp_path']}"))
249
		chmod("{$g['tmp_path']}", 01777);
250
	if (!is_dir("{$g['vardb_path']}/rrd"))
251
		mkdir("{$g['vardb_path']}/rrd", 0775);
252

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

    
255
	/* start a new apinger process */
256
	@unlink("{$g['tmp_path']}/apinger.status");
257
	sleep(1);
258
	mwexec_bg("/usr/local/sbin/apinger -c {$g['varetc_path']}/apinger.conf");
259

    
260
	return 0;
261
}
262

    
263
/* return the status of the apinger targets as a array */
264
function return_gateways_status($byname = false) {
265
	global $config, $g;
266

    
267
	$apingerstatus = array();
268
	if (file_exists("{$g['tmp_path']}/apinger.status")) {
269
		$apingerstatus = file("{$g['tmp_path']}/apinger.status");
270
	}
271

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

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

    
305
			$status[$target]['monitorip'] = $tgtip;
306
			$status[$target]['srcip'] = $srcip;
307
			$status[$target]['name'] = $gwitem['name'];
308
			$status[$target]['lastcheck'] = date('r');
309
			$status[$target]['delay'] = "0.0ms";
310
			$status[$target]['loss'] = "0.0%";
311
			$status[$target]['status'] = "none";
312
		}
313
	}
314
	return($status);
315
}
316

    
317
/* Return all configured gateways on the system */
318
function return_gateways_array($disabled = false) {
319
	global $config, $g;
320

    
321
	$gateways_arr = array();
322

    
323
	$found_defaultv4 = 0;
324
	$found_defaultv6 = 0;
325

    
326
	$i = 0;
327
	/* Process/add all the configured gateways. */
328
	if (is_array($config['gateways']['gateway_item'])) {
329
		foreach($config['gateways']['gateway_item'] as $gateway) {
330
			/* skip disabled interfaces */
331
			if(!isset($config['interfaces'][$gateway['interface']]['enable']))
332
				continue;
333
			
334
			/* if the gateway is dynamic and we can find the IP, Great! */
335
			if(empty($gateway['gateway']) || ($gateway['gateway'] == "dynamic")) {
336
				$gateway['ipprotocol'] = "inet";
337
				$gateway['gateway'] = get_interface_gateway($gateway['interface']);
338
				if($gateway['gateway'] == "dynamic") {
339
					$dynstr = $gateway['gateway'];
340
				}
341
				/* no IP address found, set to dynamic */
342
				if(! is_ipaddrv4($gateway['gateway'])) {
343
					$gateway['gateway'] = "{$dynstr}";
344
				}
345
				$gateway['dynamic'] = true;
346
			}
347
			/* if the gateway is dynamic6 and we can find the IPv6, Great! */
348
			if(empty($gateway['gateway']) || ($gateway['gateway'] == "dynamic6")) {
349
				$gateway['ipprotocol'] = "inet6";
350
				$gateway['gateway'] = get_interface_gateway_v6($gateway['interface']);
351
				if($gateway['gateway'] == "dynamic6") {
352
					$dynstr = $gateway['gateway'];
353
				}
354
				/* no IPv6 address found, set to dynamic6 */
355
				if(! is_ipaddrv6($gateway['gateway'])) {
356
					$gateway['gateway'] = "{$dynstr}";
357
				}
358
				$gateway['dynamic'] = true;
359
			}
360
			if(is_ipaddrv4($gateway['gateway']))
361
				$gateway['ipprotocol'] = "inet";
362
			if(is_ipaddrv6($gateway['gateway']))
363
				$gateway['ipprotocol'] = "inet6";
364
			if (isset($gateway['monitor_disable']))
365
				$gateway['monitor_disable'] = true;
366
			else if (empty($gateway['monitor']))
367
				$gateway['monitor'] = $gateway['gateway'];
368

    
369
			$gateway['friendlyiface'] = $gateway['interface'];
370
			$gateway['interface'] = get_real_interface($gateway['interface']);
371

    
372
			/* entry has a default flag, use it */
373
			if (isset($gateway['defaultgw'])) {
374
				if($gateway['ipprotocol'] == "inet") {
375
					$gateway['defaultgw'] = true;
376
					$found_defaultv4 = 1;
377
				}
378
				if($gateway['ipprotocol'] == "inet6") {
379
					$gateway['defaultgw'] = true;
380
					$found_defaultv6 = 1;
381
				}
382
			}
383
			/* FIXME: Should this be enabled.
384
			 * Some interface like wan might be default but have no info recorded 
385
			 * the config. */
386
			/* this is a fallback if all else fails and we want to get packet out @smos */
387
			if (!isset($gateway['defaultgw'])) {
388
				if (($gateway['friendlyiface'] == "wan") && ($found_defaultv4 == 0)) {
389
					if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgw")) {
390
						$gateway['defaultgw'] = true;
391
						$found_defaultv4 = 1;
392
					}
393
				}
394
				if (($gateway['friendlyiface'] == "wan") && ($found_defaultv6 == 0)) {
395
					if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgwv6")) {
396
						$gateway['defaultgw'] = true;
397
						$found_defaultv6 = 1;
398
					}
399
				}
400
			}
401
			/* include the gateway index as the attribute */
402
			$gateway['attribute'] = $i;
403

    
404
			$gateways_arr[$gateway['name']] = $gateway;
405
			unset($gateway);
406
			$i++;
407
		}
408
	} 
409

    
410
	/* Loop through all interfaces with a gateway and add it to a array */
411
	if ($disabled == false)
412
		$iflist = get_configured_interface_with_descr();
413
	else
414
		$iflist = get_configured_interface_with_descr(false, true);
415

    
416
	/* Process/add dynamic v4 gateways. */
417
	foreach($iflist as $ifname => $friendly ) {
418
		if(! interface_has_gateway($ifname))
419
			continue;
420

    
421
		if (empty($config['interfaces'][$ifname]))
422
			continue;
423

    
424
		$ifcfg = &$config['interfaces'][$ifname];
425
		if(!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr']))
426
			continue;
427

    
428
		if(!isset($ifcfg['enable']))
429
			continue;
430
			
431
		$ctype = "";
432
		switch($ifcfg['ipaddr']) {
433
			case "dhcp":
434
			case "pppoe":
435
			case "pptp":
436
				$ctype = strtoupper($ifcfg['ipaddr']);
437
				break;
438
		}
439
		$ctype = "_". strtoupper($ctype);
440

    
441
		$gateway = array();
442
		$gateway['dynamic'] = false;
443
		$gateway['ipprotocol'] = "inet";
444
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
445
		$gateway['interface'] = get_real_interface($ifname);
446
		$gateway['friendlyiface'] = $ifname;
447
		$gateway['name'] = "{$friendly}{$ctype}";
448
		$gateway['attribute'] = "system";
449
	
450
		if (($gateway['dynamic'] === "default") && ($found_defaultv4 == 0)) {
451
			$gateway['defaultgw'] = true;
452
			$gateway['dynamic'] = true;
453
			$found_defaultv4 = 1;
454
		}
455
		/* Loopback dummy for dynamic interfaces without a IP */
456
		if (!is_ipaddrv4($gateway['gateway']) && $gateway['dynamic'] == true)
457
			$gateway['gateway'] = "dynamic";
458

    
459
		/* automatically skip known static and dynamic gateways we have a array entry for */
460
		foreach($gateways_arr as $gateway_item) {
461
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name'])&& ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
462
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
463
					continue 2;
464
		}
465

    
466
		if (is_ipaddrv4($gateway['gateway']))
467
			$gateway['monitor'] = $gateway['gateway'];
468

    
469
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
470
		$gateways_arr[$gateway['name']] = $gateway;
471
		unset($gateway);
472
	}
473

    
474
	/* Process/add dynamic v6 gateways. */
475
	foreach($iflist as $ifname => $friendly ) {
476
		if(! interface_has_gatewayv6($ifname))
477
			continue;
478

    
479
		if (empty($config['interfaces'][$ifname]))
480
			continue;
481

    
482
		$ifcfg = &$config['interfaces'][$ifname];
483
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
484
			continue;
485
			
486
		if(!isset($ifcfg['enable']))
487
			continue;
488

    
489
		$ctype = "";
490
		switch($ifcfg['ipaddrv6']) {
491
			case "dhcp6":
492
			case "6to4":
493
			case "6rd":
494
				$ctype = strtoupper($ifcfg['ipaddrv6']);
495
				break;
496
		}
497
		$ctype = "_". strtoupper($ctype);
498

    
499
		$gateway = array();
500
		$gateway['dynamic'] = false;
501
		$gateway['ipprotocol'] = "inet6";
502
		$gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
503
		switch($ifcfg['ipaddrv6']) {
504
			case "6to4":
505
				$gateway['interface'] = "stf0";
506
				$gateway['dynamic'] = "default";
507
				break;
508
			case "6rd":
509
				$gateway['interface'] = "srd0";
510
				$gateway['dynamic'] = "default";
511
				break;
512
			default:
513
				$gateway['interface'] = get_real_interface($ifname);
514
				break;
515
		}
516
		$gateway['friendlyiface'] = $ifname;
517
		$gateway['name'] = "{$friendly}{$ctype}";
518
		$gateway['attribute'] = "system";
519
	
520
		if (($gateway['dynamic'] === "default")  && ($found_defaultv6 == 0)) {
521
			$gateway['defaultgw'] = true;
522
			$gateway['dynamic'] = true;
523
			$found_defaultv6 = 1;
524
		}
525

    
526
		/* Loopback dummy for dynamic interfaces without a IP */
527
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
528
			$gateway['gateway'] = "dynamic6";
529

    
530
		/* automatically skip known static and dynamic gateways we have a array entry for */
531
		foreach($gateways_arr as $gateway_item) {
532
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
533
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
534
					continue 2;
535
		}
536

    
537
		if (is_ipaddrv6($gateway['gateway']))
538
			$gateway['monitor'] = $gateway['gateway'];
539

    
540
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
541
		$gateways_arr[$gateway['name']] = $gateway;
542
		unset($gateway);
543
	}
544
	return($gateways_arr);
545
}
546

    
547
/*
548
 * Return an array with all gateway groups with name as key
549
 * All gateway groups will be processed before returning the array.
550
 */
551
function return_gateway_groups_array() {
552
	global $config, $g;
553

    
554
	/* fetch the current gateways status */
555
	$gateways_status = return_gateways_status(true);
556
	$gateways_arr = return_gateways_array();
557
	$gateway_groups_array = array();
558

    
559
	if (isset($config['system']['gw_switch_default'])) {
560
		/* 
561
		 * NOTE: The code below is meant to replace the default gateway when it goes down.
562
		 *	This facilitates services running on pfSense itself and are not handled by a PBR to continue working.
563
		 */
564
		$upgw = "";
565
		$dfltgwdown = false;
566
		$dfltgwfound = false;
567
		foreach ($gateways_arr as $gwname => $gwsttng) {
568
			if (isset($gwsttng['defaultgw'])) {
569
				$dfltgwfound = true;
570
				$dfltgwname = $gwname;
571
				if (!isset($gwsttng['monitor_disable']) && stristr($gateways_status[$gwname]['status'], "down"))
572
					$dfltgwdown = true;
573
			}
574
			/* Keep a record of the last up gateway */
575
			/* XXX: Blacklist lan for now since it might cause issues to those who have a gateway set for it */
576
			if (empty($upgw) && (isset($gwsttng['monitor_disable']) || !stristr($gateways_status[$gwname]['status'], "down")) && $gwsttng[$gwname]['friendlyiface'] != "lan")
577
				$upgw = $gwname;
578
			if ($dfltgwdown == true && !empty($upgw))
579
				break;
580
		}
581
		if ($dfltgwfound == false) {
582
			$gwname = convert_friendly_interface_to_friendly_descr("wan");
583
			if (!empty($gateways_status[$gwname]) && stristr($gateways_status[$gwname]['status'], "down"))
584
				$dfltgwdown = true;
585
		}
586
		if ($dfltgwdown == true && !empty($upgw)) {
587
			if (preg_match("/dynamic", $gateways_arr[$upgw]['gateway']))
588
				$gateways_arr[$upgw]['gateway'] = get_interface_gateway($gateways_arr[$upgw]['friendlyiface']);
589
			if (is_ipaddr($gateways_arr[$upgw]['gateway'])) {
590
				log_error("Default gateway down setting {$upgw} as default!");
591
				mwexec("/sbin/route change -inet default {$gateways_arr[$upgw]['gateway']}");
592
			}
593
		} else {
594
			$defaultgw = trim(`/sbin/route -n get -inet default | /usr/bin/grep gateway | /usr/bin/sed 's/gateway://g'`, " \n");
595
			if ($defaultgw != $gateways_arr[$dfltgwname]['gateway'])
596
				mwexec("/sbin/route change -inet default {$gateways_arr[$dfltgwname]['gateway']}");
597
		}
598
				
599
		unset($upgw, $dfltgwfound, $dfltgwdown, $gwname, $gwsttng);
600
	}
601

    
602
	if (is_array($config['gateways']['gateway_group'])) {
603
		foreach($config['gateways']['gateway_group'] as $group) {
604
			/* create array with group gateways members seperated by tier */
605
			$tiers = array();
606
			$backupplan = array();
607
			foreach($group['item'] as $item) {
608
				$itemsplit = explode("|", $item);
609
				$tier = $itemsplit[1];
610
				$gwname = $itemsplit[0];
611

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

    
615
				/* check if the gateway is available before adding it to the array */
616
				if (!empty($gateways_status[$gwname])) {
617
					$status = $gateways_status[$gwname];
618
					$gwdown = false;
619
					if (stristr($status['status'], "down")) {
620
						$msg = sprintf(gettext("MONITOR: %s is down, removing from routing group"), $gwname);
621
						$gwdown = true;
622
					} else if (stristr($status['status'], "loss") && strstr($group['trigger'], "loss")) {
623
						/* packet loss */
624
						$msg = sprintf(gettext("MONITOR: %s has packet loss, removing from routing group"), $gwname);
625
						$gwdown = true;
626
					} else if (stristr($status['status'], "delay") && strstr($group['trigger'] , "latency")) {
627
						/* high latency */
628
						$msg = sprintf(gettext("MONITOR: %s has high latency, removing from routing group"), $gwname);
629
						$gwdown = true;
630
					}
631
					if ($gwdown == true) {
632
						log_error($msg);
633
						notify_via_growl($msg);
634
						notify_via_smtp($msg);
635
					} else
636
						/* Online add member */
637
						$tiers[$tier][] = $gwname;
638
				} else if (isset($gateways_arr[$gwname]['monitor_disable']))
639
					$tiers[$tier][] = $gwname;
640
			}
641
			$tiers_count = count($tiers);
642
			if($tiers_count == 0) {
643
				/* Oh dear, we have no members! Engage Plan B */
644
				if (!$g['booting']) {
645
					$msg = gettext("Gateways status could not be determined, considering all as up/active.");
646
					log_error($msg);
647
					notify_via_growl($msg);
648
					notify_via_smtp($msg);
649
				}
650
				$tiers = $backupplan;
651
			}
652
			/* sort the tiers array by the tier key */
653
			ksort($tiers);
654

    
655
			/* we do not really foreach the tiers as we stop after the first tier */
656
			foreach($tiers as $tier) {
657
				/* process all gateways in this tier */
658
				foreach($tier as $member) {
659
					/* determine interface gateway */
660
					if (isset($gateways_arr[$member])) {
661
						$gateway = $gateways_arr[$member];
662
						$int = $gateway['interface'];
663
						$gatewayip = "";
664
						if(is_ipaddr($gateway['gateway'])) 
665
							$gatewayip = $gateway['gateway'];
666
						else if ($int <> "")
667
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
668
					
669
						if (($int <> "") && is_ipaddr($gatewayip)) {
670
							$groupmember = array();
671
							$groupmember['int']  = $int;
672
							$groupmember['gwip']  = $gatewayip;
673
							$groupmember['weight']  = isset($gateway['weight']) ? $gateway['weight'] : 1;
674
							$gateway_groups_array[$group['name']][] = $groupmember;
675
						}
676
					}
677
				}
678
				/* we should have the 1st available tier now, exit stage left */
679
				break;
680
			}
681
		}
682
	}
683
	return ($gateway_groups_array);
684
}
685

    
686
/* Update DHCP WAN Interface ip address in gateway group item */
687
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
688
	global $config, $g;
689
	foreach($config['gateways']['gateway_item'] as & $gw) {	
690
		if($gw['interface'] == $interface) {
691
			$current_gw = get_interface_gateway($interface);
692
			if($gw['gateway'] <> $current_gw) {
693
				$gw['gateway'] = $current_gw;
694
				$changed = true;
695
			}
696
		}
697
	}
698
	if($changed && $current_gw)
699
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interfac, $current_gw));
700
}
701

    
702
function lookup_gateway_ip_by_name($name) {
703

    
704
	$gateways_arr = return_gateways_array();
705
        foreach ($gateways_arr as $gname => $gw) {
706
                if ($gw['name'] == $name || $gname == $name)
707
                        return $gw['gateway'];
708
        }
709

    
710
	return false;
711
}
712

    
713
function lookup_gateway_monitor_ip_by_name($name) {
714

    
715
        $gateways_arr = return_gateways_array();
716
	if (!empty($gateways_arr[$name])) {
717
		$gateway = $gateways_arr[$name];
718
		if(!is_ipaddr($gateway['monitor']))
719
			return $gateway['gateway'];
720

    
721
		return $gateway['monitor'];
722
        }
723

    
724
        return (false);
725
}
726

    
727
function lookup_gateway_interface_by_name($name) {
728

    
729
        $gateways_arr = return_gateways_array();
730
	if (!empty($gateways_arr[$name])) {
731
		$interfacegw = $gateway['interface'];
732
		return ($interfacegw);
733
        }
734

    
735
        return (false);
736
}
737

    
738
function get_interface_gateway($interface, &$dynamic = false) {
739
	global $config, $g;
740

    
741
	$gw = NULL;
742

    
743
	$gwcfg = $config['interfaces'][$interface];
744
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
745
		foreach($config['gateways']['gateway_item'] as $gateway) {
746
			if(($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
747
				$gw = $gateway['gateway'];
748
				break;
749
			}
750
		}
751
	}
752

    
753
	// for dynamic interfaces we handle them through the $interface_router file.
754
	if (!is_ipaddrv4($gw) && !is_ipaddrv4($gwcfg['ipaddr'])) {
755
		$realif = get_real_interface($interface);
756
		if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
757
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
758
			$dynamic = true;
759
		}
760
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw"))
761
			$dynamic = "default";
762
			
763
	}
764

    
765
	/* return gateway */
766
	return ($gw);
767
}
768

    
769
function get_interface_gateway_v6($interface, &$dynamic = false) {
770
	global $config, $g;
771

    
772
	$gw = NULL;
773
	$gwcfg = $config['interfaces'][$interface];
774
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
775
		foreach($config['gateways']['gateway_item'] as $gateway) {
776
			if(($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
777
				$gw = $gateway['gateway'];
778
				break;
779
			}
780
		}
781
	}
782

    
783
	// for dynamic interfaces we handle them through the $interface_router file.
784
	if (!is_ipaddrv6($gw) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
785
			$realif = get_real_interface($interface);
786
			if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
787
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
788
				$dynamic = true;
789
			}
790
			if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6"))
791
				$dynamic = "default";
792
			
793
	}
794
	/* return gateway */
795
	return ($gw);
796
}
797

    
798
/* Check a IP address against a gateway IP or name
799
 * to verify it's address family */
800
function validate_address_family($ipaddr, $gwname) {
801
	$v4ip = false;
802
	$v6ip = false;
803
	$v4gw = false;
804
	$v6gw = false;
805

    
806
	if(is_ipaddrv4($ipaddr))
807
		$v4ip = true;
808
	if(is_ipaddrv6($ipaddr))
809
		$v6ip = true;
810
	if(is_ipaddrv4($gwname))
811
		$v4gw = true;
812
	if(is_ipaddrv6($gwname))
813
		$v6gw = true;
814

    
815
	if($v4ip && $v4gw)
816
		return true;
817
	if($v6ip && $v6gw)
818
		return true;
819

    
820
	/* still no match, carry on, lookup gateways */
821
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
822
		$v4gw = true;
823
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
824
		$v6gw = true;
825
	/* are they dynamic */
826
	switch($gwname) {
827
		case "dynamic":
828
			$v4gw = true;
829
			break;
830
		case "dynamic6":
831
			$v6gw = true;
832
			break;
833
	}
834

    
835
	if($v4ip && $v4gw)
836
		return true;
837
	if($v6ip && $v6gw)
838
		return true;
839
	
840
	return false;
841
}
842

    
843

    
844
?>
(25-25/65)