Project

General

Profile

Download (27.1 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
			if(is_ipaddrv6($gateway['gateway'])) {
238
				$inetfamily = "-inet6";
239
			} else {
240
				$inetfamily = "-inet";
241
			}
242
			mwexec("/sbin/route change {$inetfamily} -host " . escapeshellarg($gateway['monitor']) .
243
				" " . escapeshellarg($gateway['gateway']), true);
244
		}
245

    
246
		$apingerconfig .= $alarmscfg;
247
		$apingerconfig .= $apingercfg;
248
	}
249
	fwrite($fd, $apingerconfig);
250
	fclose($fd);
251

    
252
	killbypid("{$g['varrun_path']}/apinger.pid");
253
	if (is_dir("{$g['tmp_path']}"))
254
		chmod("{$g['tmp_path']}", 01777);
255
	if (!is_dir("{$g['vardb_path']}/rrd"))
256
		mkdir("{$g['vardb_path']}/rrd", 0775);
257

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

    
260
	/* start a new apinger process */
261
	@unlink("{$g['tmp_path']}/apinger.status");
262
	sleep(1);
263
	mwexec_bg("/usr/local/sbin/apinger -c {$g['varetc_path']}/apinger.conf");
264

    
265
	return 0;
266
}
267

    
268
/* return the status of the apinger targets as a array */
269
function return_gateways_status($byname = false) {
270
	global $config, $g;
271

    
272
	$apingerstatus = array();
273
	if (file_exists("{$g['tmp_path']}/apinger.status")) {
274
		$apingerstatus = file("{$g['tmp_path']}/apinger.status");
275
	}
276

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

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

    
310
			$status[$target]['monitorip'] = $tgtip;
311
			$status[$target]['srcip'] = $srcip;
312
			$status[$target]['name'] = $gwitem['name'];
313
			$status[$target]['lastcheck'] = date('r');
314
			$status[$target]['delay'] = "0.0ms";
315
			$status[$target]['loss'] = "0.0%";
316
			$status[$target]['status'] = "none";
317
		}
318
	}
319
	return($status);
320
}
321

    
322
/* Return all configured gateways on the system */
323
function return_gateways_array($disabled = false) {
324
	global $config, $g;
325

    
326
	$gateways_arr = array();
327

    
328
	$found_defaultv4 = 0;
329
	$found_defaultv6 = 0;
330

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

    
374
			$gateway['friendlyiface'] = $gateway['interface'];
375
			$gateway['interface'] = get_real_interface($gateway['interface']);
376

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

    
409
			$gateways_arr[$gateway['name']] = $gateway;
410
			unset($gateway);
411
			$i++;
412
		}
413
	} 
414

    
415
	/* Loop through all interfaces with a gateway and add it to a array */
416
	if ($disabled == false)
417
		$iflist = get_configured_interface_with_descr();
418
	else
419
		$iflist = get_configured_interface_with_descr(false, true);
420

    
421
	/* Process/add dynamic v4 gateways. */
422
	foreach($iflist as $ifname => $friendly ) {
423
		if(! interface_has_gateway($ifname))
424
			continue;
425

    
426
		if (empty($config['interfaces'][$ifname]))
427
			continue;
428

    
429
		$ifcfg = &$config['interfaces'][$ifname];
430
		if(!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr']))
431
			continue;
432

    
433
		if(!isset($ifcfg['enable']))
434
			continue;
435
			
436
		$ctype = "";
437
		switch($ifcfg['ipaddr']) {
438
			case "dhcp":
439
			case "pppoe":
440
			case "pptp":
441
				$ctype = strtoupper($ifcfg['ipaddr']);
442
				break;
443
			default:
444
				if (substr($ifcfg['if'], 0, 5) ==  "ovpnc")
445
					$ctype = "VPNv4";
446
				break;
447
		}
448
		$ctype = "_". strtoupper($ctype);
449

    
450
		$gateway = array();
451
		$gateway['dynamic'] = false;
452
		$gateway['ipprotocol'] = "inet";
453
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
454
		$gateway['interface'] = get_real_interface($ifname);
455
		$gateway['friendlyiface'] = $ifname;
456
		$gateway['name'] = "{$friendly}{$ctype}";
457
		$gateway['attribute'] = "system";
458
	
459
		if (($gateway['dynamic'] === "default") && ($found_defaultv4 == 0)) {
460
			$gateway['defaultgw'] = true;
461
			$gateway['dynamic'] = true;
462
			$found_defaultv4 = 1;
463
		}
464
		/* Loopback dummy for dynamic interfaces without a IP */
465
		if (!is_ipaddrv4($gateway['gateway']) && $gateway['dynamic'] == true)
466
			$gateway['gateway'] = "dynamic";
467

    
468
		/* automatically skip known static and dynamic gateways we have a array entry for */
469
		foreach($gateways_arr as $gateway_item) {
470
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name'])&& ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
471
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
472
					continue 2;
473
		}
474

    
475
		if (is_ipaddrv4($gateway['gateway']))
476
			$gateway['monitor'] = $gateway['gateway'];
477

    
478
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
479
		$gateways_arr[$gateway['name']] = $gateway;
480
		unset($gateway);
481
	}
482

    
483
	/* Process/add dynamic v6 gateways. */
484
	foreach($iflist as $ifname => $friendly ) {
485
		if(! interface_has_gatewayv6($ifname))
486
			continue;
487

    
488
		if (empty($config['interfaces'][$ifname]))
489
			continue;
490

    
491
		$ifcfg = &$config['interfaces'][$ifname];
492
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
493
			continue;
494
			
495
		if(!isset($ifcfg['enable']))
496
			continue;
497

    
498
		$ctype = "";
499
		switch($ifcfg['ipaddrv6']) {
500
			case "slaac":
501
			case "dhcp6":
502
			case "6to4":
503
			case "6rd":
504
				$ctype = strtoupper($ifcfg['ipaddrv6']);
505
				break;
506
			default:
507
				if (substr($ifcfg['if'], 0, 5) ==  "ovpnc")
508
					$ctype = "VPNv6";
509
				break;
510
		}
511
		$ctype = "_". strtoupper($ctype);
512

    
513
		$gateway = array();
514
		$gateway['dynamic'] = false;
515
		$gateway['ipprotocol'] = "inet6";
516
		$gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
517
		switch($ifcfg['ipaddrv6']) {
518
			case "6to4":
519
				$gateway['interface'] = "stf0";
520
				$gateway['dynamic'] = "default";
521
				break;
522
			case "6rd":
523
				$gateway['interface'] = "stf0";
524
				$gateway['dynamic'] = "default";
525
				break;
526
			default:
527
				$gateway['interface'] = get_real_interface($ifname);
528
				break;
529
		}
530
		$gateway['friendlyiface'] = $ifname;
531
		$gateway['name'] = "{$friendly}{$ctype}";
532
		$gateway['attribute'] = "system";
533
	
534
		if (($gateway['dynamic'] === "default")  && ($found_defaultv6 == 0)) {
535
			$gateway['defaultgw'] = true;
536
			$gateway['dynamic'] = true;
537
			$found_defaultv6 = 1;
538
		}
539

    
540
		/* Loopback dummy for dynamic interfaces without a IP */
541
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
542
			$gateway['gateway'] = "dynamic6";
543

    
544
		/* automatically skip known static and dynamic gateways we have a array entry for */
545
		foreach($gateways_arr as $gateway_item) {
546
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
547
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
548
					continue 2;
549
		}
550

    
551
		if (is_ipaddrv6($gateway['gateway']))
552
			$gateway['monitor'] = $gateway['gateway'];
553

    
554
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
555
		$gateways_arr[$gateway['name']] = $gateway;
556
		unset($gateway);
557
	}
558
	return($gateways_arr);
559
}
560

    
561
/*
562
 * Return an array with all gateway groups with name as key
563
 * All gateway groups will be processed before returning the array.
564
 */
565
function return_gateway_groups_array() {
566
	global $config, $g;
567

    
568
	/* fetch the current gateways status */
569
	$gateways_status = return_gateways_status(true);
570
	$gateways_arr = return_gateways_array();
571
	$gateway_groups_array = array();
572

    
573
	if (isset($config['system']['gw_switch_default'])) {
574
		/* 
575
		 * NOTE: The code below is meant to replace the default gateway when it goes down.
576
		 *	This facilitates services running on pfSense itself and are not handled by a PBR to continue working.
577
		 */
578
		$upgw = "";
579
		$dfltgwdown = false;
580
		$dfltgwfound = false;
581
		foreach ($gateways_arr as $gwname => $gwsttng) {
582
			if (isset($gwsttng['defaultgw'])) {
583
				$dfltgwfound = true;
584
				$dfltgwname = $gwname;
585
				if (!isset($gwsttng['monitor_disable']) && stristr($gateways_status[$gwname]['status'], "down"))
586
					$dfltgwdown = true;
587
			}
588
			/* Keep a record of the last up gateway */
589
			/* XXX: Blacklist lan for now since it might cause issues to those who have a gateway set for it */
590
			if (empty($upgw) && (isset($gwsttng['monitor_disable']) || !stristr($gateways_status[$gwname]['status'], "down")) && $gwsttng[$gwname]['friendlyiface'] != "lan")
591
				$upgw = $gwname;
592
			if ($dfltgwdown == true && !empty($upgw))
593
				break;
594
		}
595
		if ($dfltgwfound == false) {
596
			$gwname = convert_friendly_interface_to_friendly_descr("wan");
597
			if (!empty($gateways_status[$gwname]) && stristr($gateways_status[$gwname]['status'], "down"))
598
				$dfltgwdown = true;
599
		}
600
		if ($dfltgwdown == true && !empty($upgw)) {
601
			if (preg_match("/dynamic", $gateways_arr[$upgw]['gateway']))
602
				$gateways_arr[$upgw]['gateway'] = get_interface_gateway($gateways_arr[$upgw]['friendlyiface']);
603
			if (is_ipaddr($gateways_arr[$upgw]['gateway'])) {
604
				log_error("Default gateway down setting {$upgw} as default!");
605
				if(is_ipaddrv6($gateways_arr[$upgw]['gateway'])) {
606
					$inetfamily = "-inet6";
607
				} else {
608
					$inetfamily = "-inet";
609
				}
610
				mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$upgw]['gateway']}");
611
			}
612
		} else {
613
			$defaultgw = trim(`/sbin/route -n get -inet default | /usr/bin/grep gateway | /usr/bin/sed 's/gateway://g'`, " \n");
614
			if(is_ipaddrv6($gateways_arr[$dfltgwname]['gateway'])) {
615
				$inetfamily = "-inet6";
616
			} else {
617
				$inetfamily = "-inet";
618
			}
619
			if ($defaultgw != $gateways_arr[$dfltgwname]['gateway'])
620
				mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$dfltgwname]['gateway']}");
621
		}
622
				
623
		unset($upgw, $dfltgwfound, $dfltgwdown, $gwname, $gwsttng);
624
	}
625

    
626
	if (is_array($config['gateways']['gateway_group'])) {
627
		foreach($config['gateways']['gateway_group'] as $group) {
628
			/* create array with group gateways members seperated by tier */
629
			$tiers = array();
630
			$backupplan = array();
631
			foreach($group['item'] as $item) {
632
				$itemsplit = explode("|", $item);
633
				$tier = $itemsplit[1];
634
				$gwname = $itemsplit[0];
635

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

    
639
				/* check if the gateway is available before adding it to the array */
640
				if (!empty($gateways_status[$gwname])) {
641
					$status = $gateways_status[$gwname];
642
					$gwdown = false;
643
					if (stristr($status['status'], "down")) {
644
						$msg = sprintf(gettext("MONITOR: %s is down, removing from routing group"), $gwname);
645
						$gwdown = true;
646
					} else if (stristr($status['status'], "loss") && strstr($group['trigger'], "loss")) {
647
						/* packet loss */
648
						$msg = sprintf(gettext("MONITOR: %s has packet loss, removing from routing group"), $gwname);
649
						$gwdown = true;
650
					} else if (stristr($status['status'], "delay") && strstr($group['trigger'] , "latency")) {
651
						/* high latency */
652
						$msg = sprintf(gettext("MONITOR: %s has high latency, removing from routing group"), $gwname);
653
						$gwdown = true;
654
					}
655
					if ($gwdown == true) {
656
						log_error($msg);
657
						notify_via_growl($msg);
658
						notify_via_smtp($msg);
659
					} else
660
						/* Online add member */
661
						$tiers[$tier][] = $gwname;
662
				} else if (isset($gateways_arr[$gwname]['monitor_disable']))
663
					$tiers[$tier][] = $gwname;
664
			}
665
			$tiers_count = count($tiers);
666
			if($tiers_count == 0) {
667
				/* Oh dear, we have no members! Engage Plan B */
668
				if (!$g['booting']) {
669
					$msg = gettext("Gateways status could not be determined, considering all as up/active.");
670
					log_error($msg);
671
					notify_via_growl($msg);
672
					notify_via_smtp($msg);
673
				}
674
				$tiers = $backupplan;
675
			}
676
			/* sort the tiers array by the tier key */
677
			ksort($tiers);
678

    
679
			/* we do not really foreach the tiers as we stop after the first tier */
680
			foreach($tiers as $tier) {
681
				/* process all gateways in this tier */
682
				foreach($tier as $member) {
683
					/* determine interface gateway */
684
					if (isset($gateways_arr[$member])) {
685
						$gateway = $gateways_arr[$member];
686
						$int = $gateway['interface'];
687
						$gatewayip = "";
688
						if(is_ipaddr($gateway['gateway'])) 
689
							$gatewayip = $gateway['gateway'];
690
						else if ($int <> "")
691
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
692
					
693
						if (($int <> "") && is_ipaddr($gatewayip)) {
694
							$groupmember = array();
695
							$groupmember['int']  = $int;
696
							$groupmember['gwip']  = $gatewayip;
697
							$groupmember['weight']  = isset($gateway['weight']) ? $gateway['weight'] : 1;
698
							$gateway_groups_array[$group['name']][] = $groupmember;
699
						}
700
					}
701
				}
702
				/* we should have the 1st available tier now, exit stage left */
703
				break;
704
			}
705
		}
706
	}
707
	return ($gateway_groups_array);
708
}
709

    
710
/* Update DHCP WAN Interface ip address in gateway group item */
711
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
712
	global $config, $g;
713
	foreach($config['gateways']['gateway_item'] as & $gw) {	
714
		if($gw['interface'] == $interface) {
715
			$current_gw = get_interface_gateway($interface);
716
			if($gw['gateway'] <> $current_gw) {
717
				$gw['gateway'] = $current_gw;
718
				$changed = true;
719
			}
720
		}
721
	}
722
	if($changed && $current_gw)
723
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interfac, $current_gw));
724
}
725

    
726
function lookup_gateway_ip_by_name($name) {
727

    
728
	$gateways_arr = return_gateways_array();
729
        foreach ($gateways_arr as $gname => $gw) {
730
                if ($gw['name'] == $name || $gname == $name)
731
                        return $gw['gateway'];
732
        }
733

    
734
	return false;
735
}
736

    
737
function lookup_gateway_monitor_ip_by_name($name) {
738

    
739
        $gateways_arr = return_gateways_array();
740
	if (!empty($gateways_arr[$name])) {
741
		$gateway = $gateways_arr[$name];
742
		if(!is_ipaddr($gateway['monitor']))
743
			return $gateway['gateway'];
744

    
745
		return $gateway['monitor'];
746
        }
747

    
748
        return (false);
749
}
750

    
751
function lookup_gateway_interface_by_name($name) {
752

    
753
        $gateways_arr = return_gateways_array();
754
	if (!empty($gateways_arr[$name])) {
755
		$interfacegw = $gateway['interface'];
756
		return ($interfacegw);
757
        }
758

    
759
        return (false);
760
}
761

    
762
function get_interface_gateway($interface, &$dynamic = false) {
763
	global $config, $g;
764

    
765
	$gw = NULL;
766

    
767
	$gwcfg = $config['interfaces'][$interface];
768
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
769
		foreach($config['gateways']['gateway_item'] as $gateway) {
770
			if(($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
771
				$gw = $gateway['gateway'];
772
				break;
773
			}
774
		}
775
	}
776

    
777
	// for dynamic interfaces we handle them through the $interface_router file.
778
	if (!is_ipaddrv4($gw) && !is_ipaddrv4($gwcfg['ipaddr'])) {
779
		$realif = get_real_interface($interface);
780
		if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
781
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
782
			$dynamic = true;
783
		}
784
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw"))
785
			$dynamic = "default";
786
			
787
	}
788

    
789
	/* return gateway */
790
	return ($gw);
791
}
792

    
793
function get_interface_gateway_v6($interface, &$dynamic = false) {
794
	global $config, $g;
795

    
796
	$gw = NULL;
797
	$gwcfg = $config['interfaces'][$interface];
798
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
799
		foreach($config['gateways']['gateway_item'] as $gateway) {
800
			if(($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
801
				$gw = $gateway['gateway'];
802
				break;
803
			}
804
		}
805
	}
806

    
807
	// for dynamic interfaces we handle them through the $interface_router file.
808
	if (!is_ipaddrv6($gw) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
809
			$realif = get_real_interface($interface);
810
			if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
811
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
812
				$dynamic = true;
813
			}
814
			if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6"))
815
				$dynamic = "default";
816
			
817
	}
818
	/* return gateway */
819
	return ($gw);
820
}
821

    
822
/* Check a IP address against a gateway IP or name
823
 * to verify it's address family */
824
function validate_address_family($ipaddr, $gwname) {
825
	$v4ip = false;
826
	$v6ip = false;
827
	$v4gw = false;
828
	$v6gw = false;
829

    
830
	if(is_ipaddrv4($ipaddr))
831
		$v4ip = true;
832
	if(is_ipaddrv6($ipaddr))
833
		$v6ip = true;
834
	if(is_ipaddrv4($gwname))
835
		$v4gw = true;
836
	if(is_ipaddrv6($gwname))
837
		$v6gw = true;
838

    
839
	if($v4ip && $v4gw)
840
		return true;
841
	if($v6ip && $v6gw)
842
		return true;
843

    
844
	/* still no match, carry on, lookup gateways */
845
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
846
		$v4gw = true;
847
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
848
		$v6gw = true;
849
	/* are they dynamic */
850
	switch($gwname) {
851
		case "dynamic":
852
			$v4gw = true;
853
			break;
854
		case "dynamic6":
855
			$v6gw = true;
856
			break;
857
	}
858

    
859
	if($v4ip && $v4gw)
860
		return true;
861
	if($v6ip && $v6gw)
862
		return true;
863
	
864
	return false;
865
}
866

    
867

    
868
?>
(25-25/65)