Project

General

Profile

Download (30.7 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
require_once("config.inc");
33

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

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

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

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

    
59
# pfSense apinger configuration file. Automatically Generated!
60

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
138
EOD;
139

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

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

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

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

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

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

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

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

    
266
	return 0;
267
}
268

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

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

    
278
	$status = array();
279
	foreach($apingerstatus as $line) {
280
		$info = explode("|", $line);
281
		if ($byname == false)
282
			$target = $info[0];
283
		else
284
			$target = $info[2];
285

    
286
		$status[$target]['monitorip'] = $info[0];
287
		$status[$target]['srcip'] = $info[1];
288
		$status[$target]['name'] = $info[2];
289
		$status[$target]['lastcheck'] = $info[5] ? date('r', $info[5]) : date('r');
290
		$status[$target]['delay'] = empty($info[6]) ? "0ms" : round($info[6], 1) ."ms" ;
291
		$status[$target]['loss'] = empty($info[7]) ? "0.0%" : round($info[7], 1) . "%";
292
		$status[$target]['status'] = trim($info[8]);
293
	}
294

    
295
	/* tack on any gateways that have monitoring disabled
296
	 * or are down, which could cause gateway groups to fail */
297
	$gateways_arr = return_gateways_array();
298
	foreach($gateways_arr as $gwitem) {
299
		if(isset($gwitem['monitor_disable'])) {
300
			if(!is_ipaddr($gwitem['monitorip'])) {
301
				$realif = $gwitem['interface'];
302
				$tgtip = get_interface_gateway($realif);
303
				$srcip = find_interface_ip($realif);
304
			} else {
305
				$tgtip = $gwitem['monitorip'];
306
				$srcip = find_interface_ip($realif);
307
			}
308
			if($byname == true)
309
				$target = $gwitem['name'];
310
			else
311
				$target = $tgtip;
312

    
313
			/* failsafe for down interfaces */
314
			if($target == "") {
315
				$target = $gwitem['name'];
316
				$status[$target]['name'] = $gwitem['name'];
317
				$status[$target]['lastcheck'] = date('r');
318
				$status[$target]['delay'] = "0.0ms";
319
				$status[$target]['loss'] = "100.0%";
320
				$status[$target]['status'] = "down";
321
			} else {
322
				$status[$target]['monitorip'] = $tgtip;
323
				$status[$target]['srcip'] = $srcip;
324
				$status[$target]['name'] = $gwitem['name'];
325
				$status[$target]['lastcheck'] = date('r');
326
				$status[$target]['delay'] = "0.0ms";
327
				$status[$target]['loss'] = "0.0%";
328
				$status[$target]['status'] = "none";
329
			}
330
		}
331
	}
332
	return($status);
333
}
334

    
335
/* Return all configured gateways on the system */
336
function return_gateways_array($disabled = false, $localhost = false) {
337
	global $config, $g;
338

    
339
	$gateways_arr = array();
340

    
341
	$found_defaultv4 = 0;
342
	$found_defaultv6 = 0;
343

    
344
	$interfaces_v4 = array();
345
	$interfaces_v6 = array();
346

    
347
	$i = 0;
348
	/* Process/add all the configured gateways. */
349
	if (is_array($config['gateways']['gateway_item'])) {
350
		foreach($config['gateways']['gateway_item'] as $gateway) {
351
			/* skip disabled interfaces */
352
			if(!isset($config['interfaces'][$gateway['interface']]['enable']))
353
				continue;
354

    
355
			$wancfg = $config['interfaces'][$gateway['interface']];
356
			/* getting this detection right is hard at this point because we still don't
357
			 * store the address family in the gateway item */
358
			if(is_ipaddrv4($gateway['gateway']))
359
				$gateway['ipprotocol'] = "inet";
360
			if(is_ipaddrv6($gateway['gateway']))
361
				$gateway['ipprotocol'] = "inet6";
362
			if((preg_match("/dynamic/i", $gateway['gateway'])) && (!isset($gateway['ipprotocol']))) {
363
				if(is_ipaddrv4($gateway['gateway']))
364
					$gateway['ipprotocol'] = "inet";
365
				if(is_ipaddrv6($gateway['gateway']))
366
					$gateway['ipprotocol'] = "inet6";
367
			}
368
			if((preg_match("/dynamic/i", $gateway['monitor'])) && (!isset($gateway['ipprotocol']))) {
369
				if(is_ipaddrv4($gateway['monitor']))
370
					$gateway['ipprotocol'] = "inet";
371
				if(is_ipaddrv6($gateway['monitor']))
372
					$gateway['ipprotocol'] = "inet6";
373
			}
374

    
375
			/* if the gateway is dynamic and we can find the IPv4, Great! */
376
			if(empty($gateway['gateway']) || ($gateway['gateway'] == "dynamic") && ($gateway['ipprotocol'] == "inet")) {
377
				/* we know which interfaces is dynamic, this should be made a function */
378
				switch($wancfg['ipaddr']) {
379
					case "dhcp":
380
					case "pppoe":
381
					case "pptp":
382
					case "ppp":
383
						$gateway['ipprotocol'] = "inet";
384
						$gateway['gateway'] = get_interface_gateway($gateway['interface']);
385
						if($gateway['gateway'] == "dynamic") {
386
							$dynstr = $gateway['gateway'];
387
						}
388
						/* no IP address found, set to dynamic */
389
						if(! is_ipaddrv4($gateway['gateway'])) {
390
							$gateway['gateway'] = "{$dynstr}";
391
						}
392
						$gateway['dynamic'] = true;
393
						break;
394
				}
395
			}
396

    
397
			/* if the gateway is dynamic6 and we can find the IPv6, Great! */
398
			if(empty($gateway['gateway']) || ($gateway['gateway'] == "dynamic")  && ($gateway['ipprotocol'] == "inet6")) {
399
				/* we know which interfaces is dynamic, this should be made a function, and for v6 too */
400
				switch($wancfg['ipaddrv6']) {
401
					case "6rd":
402
					case "6to4":
403
					case "dhcp6":
404
						$gateway['ipprotocol'] = "inet6";
405
						$gateway['gateway'] = get_interface_gateway_v6($gateway['interface']);
406
						if($gateway['gateway'] == "dynamic6") {
407
							$dynstr = $gateway['gateway'];
408
						}
409
						/* no IPv6 address found, set to dynamic6 */
410
						if(! is_ipaddrv6($gateway['gateway'])) {
411
							$gateway['gateway'] = "{$dynstr}";
412
						}
413
						$gateway['dynamic'] = true;
414
						break;
415
				}
416
			}
417

    
418
			if (isset($gateway['monitor_disable']))
419
				$gateway['monitor_disable'] = true;
420
			else if (empty($gateway['monitor']))
421
				$gateway['monitor'] = $gateway['gateway'];
422

    
423
			$gateway['friendlyiface'] = $gateway['interface'];
424

    
425
			/* special treatment for tunnel interfaces */
426
			if($gateway['ipprotocol'] == "inet6") {
427
				switch($wancfg['ipaddrv6']) {
428
					case "6rd":
429
					case "6to4":
430
						$gateway['interface'] = "stf0";
431
						break;
432
					default:
433
						$gateway['interface'] = get_real_interface($gateway['interface']);
434
						break;
435
				}
436
			}
437
			if($gateway['ipprotocol'] == "inet") {
438
				$gateway['interface'] = get_real_interface($gateway['interface']);
439
			}
440

    
441
			/* entry has a default flag, use it */
442
			if (isset($gateway['defaultgw'])) {
443
				if($gateway['ipprotocol'] == "inet") {
444
					$gateway['defaultgw'] = true;
445
					$found_defaultv4 = 1;
446
				}
447
				if($gateway['ipprotocol'] == "inet6") {
448
					$gateway['defaultgw'] = true;
449
					$found_defaultv6 = 1;
450
				}
451
			}
452
			/* FIXME: Should this be enabled.
453
			 * Some interface like wan might be default but have no info recorded 
454
			 * the config. */
455
			/* this is a fallback if all else fails and we want to get packets out @smos */
456
			if (!isset($gateway['defaultgw'])) {
457
				if (($gateway['friendlyiface'] == "wan") && ($found_defaultv4 == 0)) {
458
					if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgw")) {
459
						$gateway['defaultgw'] = true;
460
						$found_defaultv4 = 1;
461
					}
462
				}
463
				if (($gateway['friendlyiface'] == "wan") && ($found_defaultv6 == 0)) {
464
					if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgwv6")) {
465
						$gateway['defaultgw'] = true;
466
						$found_defaultv6 = 1;
467
					}
468
				}
469
			}
470
			/* include the gateway index as the attribute */
471
			$gateway['attribute'] = $i;
472

    
473
			/* tack a item on the array to keep track of dynamic interfaces */
474
			if($gateway['ipprotocol'] == "inet")
475
				$interfaces_v4[] = $gateway['friendlyiface'];
476

    
477
			if($gateway['ipprotocol'] == "inet6")
478
				$interfaces_v6[] = $gateway['friendlyiface'];
479

    
480
			$gateways_arr[$gateway['name']] = $gateway;
481
			unset($gateway);
482
			$i++;
483
		}
484
	}
485

    
486
	/* Loop through all interfaces with a gateway and add it to a array */
487
	if ($disabled == false)
488
		$iflist = get_configured_interface_with_descr();
489
	else
490
		$iflist = get_configured_interface_with_descr(false, true);
491

    
492
	/* Process/add dynamic v4 gateways. */
493
	foreach($iflist as $ifname => $friendly ) {
494
		if(! interface_has_gateway($ifname))
495
			continue;
496

    
497
		if (empty($config['interfaces'][$ifname]))
498
			continue;
499

    
500
		$ifcfg = &$config['interfaces'][$ifname];
501
		if(!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr']))
502
			continue;
503

    
504
		if(!isset($ifcfg['enable']))
505
			continue;
506

    
507
		if(in_array($ifname, $interfaces_v4))
508
			continue;
509
			
510
		$ctype = "";
511
		switch($ifcfg['ipaddr']) {
512
			case "dhcp":
513
			case "pppoe":
514
			case "pptp":
515
			case "ppp":
516
				$ctype = strtoupper($ifcfg['ipaddr']);
517
				break;
518
			default:
519
				if (substr($ifcfg['if'], 0, 5) ==  "ovpnc")
520
					$ctype = "VPNv4";
521
				break;
522
		}
523
		$ctype = "_". strtoupper($ctype);
524

    
525
		$gateway = array();
526
		$gateway['dynamic'] = false;
527
		$gateway['ipprotocol'] = "inet";
528
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
529
		$gateway['interface'] = get_real_interface($ifname);
530
		$gateway['friendlyiface'] = $ifname;
531
		$gateway['name'] = "{$friendly}{$ctype}";
532
		$gateway['attribute'] = "system";
533
	
534
		if (($gateway['dynamic'] === "default") && ($found_defaultv4 == 0)) {
535
			$gateway['defaultgw'] = true;
536
			$gateway['dynamic'] = true;
537
			$found_defaultv4 = 1;
538
		}
539
		/* Loopback dummy for dynamic interfaces without a IP */
540
		if (!is_ipaddrv4($gateway['gateway']) && $gateway['dynamic'] == true)
541
			$gateway['gateway'] = "dynamic";
542

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

    
550
		if (is_ipaddrv4($gateway['gateway']))
551
			$gateway['monitor'] = $gateway['gateway'];
552

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

    
558
	/* Process/add dynamic v6 gateways. */
559
	foreach($iflist as $ifname => $friendly ) {
560
		if(! interface_has_gatewayv6($ifname))
561
			continue;
562

    
563
		if (empty($config['interfaces'][$ifname]))
564
			continue;
565

    
566
		$ifcfg = &$config['interfaces'][$ifname];
567
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
568
			continue;
569
			
570
		if(!isset($ifcfg['enable']))
571
			continue;
572

    
573
		if(in_array($ifname, $interfaces_v6))
574
			continue;
575

    
576
		$ctype = "";
577
		switch($ifcfg['ipaddrv6']) {
578
			case "slaac":
579
			case "dhcp6":
580
			case "6to4":
581
			case "6rd":
582
				$ctype = strtoupper($ifcfg['ipaddrv6']);
583
				break;
584
			default:
585
				if (substr($ifcfg['if'], 0, 5) ==  "ovpnc")
586
					$ctype = "VPNv6";
587
				break;
588
		}
589
		$ctype = "_". strtoupper($ctype);
590

    
591
		$gateway = array();
592
		$gateway['dynamic'] = false;
593
		$gateway['ipprotocol'] = "inet6";
594
		$gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
595
		switch($ifcfg['ipaddrv6']) {
596
			case "6to4":
597
				$gateway['interface'] = "stf0";
598
				$gateway['dynamic'] = "default";
599
				break;
600
			case "6rd":
601
				$gateway['interface'] = "stf0";
602
				$gateway['dynamic'] = "default";
603
				break;
604
			default:
605
				$gateway['interface'] = get_real_interface($ifname);
606
				break;
607
		}
608
		$gateway['friendlyiface'] = $ifname;
609
		$gateway['name'] = "{$friendly}{$ctype}";
610
		$gateway['attribute'] = "system";
611
	
612
		if (($gateway['dynamic'] === "default")  && ($found_defaultv6 == 0)) {
613
			$gateway['defaultgw'] = true;
614
			$gateway['dynamic'] = true;
615
			$found_defaultv6 = 1;
616
		}
617

    
618
		/* Loopback dummy for dynamic interfaces without a IP */
619
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
620
			$gateway['gateway'] = "dynamic6";
621

    
622
		/* automatically skip known static and dynamic gateways we have a array entry for */
623
		foreach($gateways_arr as $gateway_item) {
624
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
625
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
626
					continue 2;
627
		}
628

    
629
		if (is_ipaddrv6($gateway['gateway']))
630
			$gateway['monitor'] = $gateway['gateway'];
631

    
632
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
633
		$gateways_arr[$gateway['name']] = $gateway;
634
		unset($gateway);
635
	}
636

    
637
	if($localhost === true) {
638
		/* attach localhost for Null routes */
639
		$gwlo4 = array();
640
		$gwlo4['name'] = "Null4";
641
		$gwlo4['interface'] = "lo0";
642
		$gwlo4['ipprotocol'] = "inet";
643
		$gwlo4['gateway'] = "127.0.0.1";
644
		$gwlo6 = array();
645
		$gwlo6['name'] = "Null6";
646
		$gwlo6['interface'] = "lo0";
647
		$gwlo6['ipprotocol'] = "inet6";
648
		$gwlo6['gateway'] = "::1";
649
		$gateways_arr['Null4'] = $gwlo4;
650
		$gateways_arr['Null6'] = $gwlo6;
651
	}
652
	return($gateways_arr);
653
}
654

    
655
/*
656
 * Return an array with all gateway groups with name as key
657
 * All gateway groups will be processed before returning the array.
658
 */
659
function return_gateway_groups_array() {
660
	global $config, $g;
661

    
662
	/* fetch the current gateways status */
663
	$gateways_status = return_gateways_status(true);
664
	$gateways_arr = return_gateways_array();
665
	$gateway_groups_array = array();
666
	$carplist = get_configured_carp_interface_list();
667

    
668
	if (isset($config['system']['gw_switch_default'])) {
669
		/* 
670
		 * NOTE: The code below is meant to replace the default gateway when it goes down.
671
		 *	This facilitates services running on pfSense itself and are not handled by a PBR to continue working.
672
		 */
673
		$upgw = "";
674
		$dfltgwdown = false;
675
		$dfltgwfound = false;
676
		foreach ($gateways_arr as $gwname => $gwsttng) {
677
			if (isset($gwsttng['defaultgw'])) {
678
				$dfltgwfound = true;
679
				$dfltgwname = $gwname;
680
				if (!isset($gwsttng['monitor_disable']) && stristr($gateways_status[$gwname]['status'], "down"))
681
					$dfltgwdown = true;
682
			}
683
			/* Keep a record of the last up gateway */
684
			/* XXX: Blacklist lan for now since it might cause issues to those who have a gateway set for it */
685
			if (empty($upgw) && (isset($gwsttng['monitor_disable']) || !stristr($gateways_status[$gwname]['status'], "down")) && $gwsttng[$gwname]['friendlyiface'] != "lan")
686
				$upgw = $gwname;
687
			if ($dfltgwdown == true && !empty($upgw))
688
				break;
689
		}
690
		if ($dfltgwfound == false) {
691
			$gwname = convert_friendly_interface_to_friendly_descr("wan");
692
			if (!empty($gateways_status[$gwname]) && stristr($gateways_status[$gwname]['status'], "down"))
693
				$dfltgwdown = true;
694
		}
695
		if ($dfltgwdown == true && !empty($upgw)) {
696
			if (preg_match("/dynamic/i", $gateways_arr[$upgw]['gateway']))
697
				$gateways_arr[$upgw]['gateway'] = get_interface_gateway($gateways_arr[$upgw]['friendlyiface']);
698
			if (is_ipaddr($gateways_arr[$upgw]['gateway'])) {
699
				log_error("Default gateway down setting {$upgw} as default!");
700
				if(is_ipaddrv6($gateways_arr[$upgw]['gateway'])) {
701
					$inetfamily = "-inet6";
702
				} else {
703
					$inetfamily = "-inet";
704
				}
705
				mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$upgw]['gateway']}");
706
			}
707
		} else {
708
			$defaultgw = trim(`/sbin/route -n get -inet default | /usr/bin/grep gateway | /usr/bin/sed 's/gateway://g'`, " \n");
709
			if(is_ipaddrv6($gateways_arr[$dfltgwname]['gateway'])) {
710
				$inetfamily = "-inet6";
711
			} else {
712
				$inetfamily = "-inet";
713
			}
714
			if ($defaultgw != $gateways_arr[$dfltgwname]['gateway'])
715
				mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$dfltgwname]['gateway']}");
716
		}
717
				
718
		unset($upgw, $dfltgwfound, $dfltgwdown, $gwname, $gwsttng);
719
	}
720
	if (is_array($config['gateways']['gateway_group'])) {
721
		foreach($config['gateways']['gateway_group'] as $group) {
722
			/* create array with group gateways members seperated by tier */
723
			$tiers = array();
724
			$backupplan = array();
725
			foreach($group['item'] as $item) {
726
				$itemsplit = explode("|", $item);
727
				$tier = $itemsplit[1];
728
				$gwname = $itemsplit[0];
729
				$vipname = $itemsplit[2];
730
				if(is_ipaddr($carplist[$vipname]))
731
					$gwvip_arr[$group['name']][$gwname] = $vipname;
732

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

    
736
				/* check if the gateway is available before adding it to the array */
737
				if (!empty($gateways_status[$gwname])) {
738
					$status = $gateways_status[$gwname];
739
					$gwdown = false;
740
					if (stristr($status['status'], "down")) {
741
						$msg = sprintf(gettext("MONITOR: %s is down, removing from routing group"), $gwname);
742
						$gwdown = true;
743
					} else if (stristr($status['status'], "loss") && strstr($group['trigger'], "loss")) {
744
						/* packet loss */
745
						$msg = sprintf(gettext("MONITOR: %s has packet loss, removing from routing group"), $gwname);
746
						$gwdown = true;
747
					} else if (stristr($status['status'], "delay") && strstr($group['trigger'] , "latency")) {
748
						/* high latency */
749
						$msg = sprintf(gettext("MONITOR: %s has high latency, removing from routing group"), $gwname);
750
						$gwdown = true;
751
					}
752
					if ($gwdown == true) {
753
						log_error($msg);
754
						notify_via_growl($msg);
755
						notify_via_smtp($msg);
756
					} else
757
						/* Online add member */
758
						$tiers[$tier][] = $gwname;
759
				} else if (isset($gateways_arr[$gwname]['monitor_disable']))
760
					$tiers[$tier][] = $gwname;
761
			}
762
			$tiers_count = count($tiers);
763
			if($tiers_count == 0) {
764
				/* Oh dear, we have no members! Engage Plan B */
765
				if (!$g['booting']) {
766
					$msg = gettext("Gateways status could not be determined, considering all as up/active.");
767
					log_error($msg);
768
					notify_via_growl($msg);
769
					notify_via_smtp($msg);
770
				}
771
				$tiers = $backupplan;
772
			}
773
			/* sort the tiers array by the tier key */
774
			ksort($tiers);
775

    
776
			/* we do not really foreach the tiers as we stop after the first tier */
777
			foreach($tiers as $tier) {
778
				/* process all gateways in this tier */
779
				foreach($tier as $member) {
780
					/* determine interface gateway */
781
					if (isset($gateways_arr[$member])) {
782
						$gateway = $gateways_arr[$member];
783
						$int = $gateway['interface'];
784
						$gatewayip = "";
785
						if(is_ipaddr($gateway['gateway'])) 
786
							$gatewayip = $gateway['gateway'];
787
						else if ($int <> "")
788
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
789
					
790
						if (($int <> "") && is_ipaddr($gatewayip)) {
791
							$groupmember = array();
792
							$groupmember['int']  = $int;
793
							$groupmember['gwip']  = $gatewayip;
794
							$groupmember['weight']  = isset($gateway['weight']) ? $gateway['weight'] : 1;
795
							if($gwvip_arr[$group['name']][$gwname] <> "")
796
								$groupmember['vip'] = $gwvip_arr[$group['name']][$gwname];
797
							$gateway_groups_array[$group['name']]['ipprotocol'] = $gateway['ipprotocol'];
798
							$gateway_groups_array[$group['name']][] = $groupmember;
799
						}
800
					}
801
				}
802
				/* we should have the 1st available tier now, exit stage left */
803
				if(is_array($gateway_groups_array[$group['name']]))
804
					break;
805
				else
806
					log_error("GATEWAYS: We did not find the first tier of the gateway group {$group['name']}! That's odd.");
807
			}
808
		}
809
	}
810
	return ($gateway_groups_array);
811
}
812

    
813
/* Update DHCP WAN Interface ip address in gateway group item */
814
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
815
	global $config, $g;
816
	foreach($config['gateways']['gateway_item'] as & $gw) {	
817
		if($gw['interface'] == $interface) {
818
			$current_gw = get_interface_gateway($interface);
819
			if($gw['gateway'] <> $current_gw) {
820
				$gw['gateway'] = $current_gw;
821
				$changed = true;
822
			}
823
		}
824
	}
825
	if($changed && $current_gw)
826
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interfac, $current_gw));
827
}
828

    
829
function lookup_gateway_ip_by_name($name) {
830

    
831
	$gateways_arr = return_gateways_array(false, true);
832
        foreach ($gateways_arr as $gname => $gw) {
833
                if ($gw['name'] == $name || $gname == $name)
834
                        return $gw['gateway'];
835
        }
836

    
837
	return false;
838
}
839

    
840
function lookup_gateway_monitor_ip_by_name($name) {
841

    
842
        $gateways_arr = return_gateways_array(false, true);
843
	if (!empty($gateways_arr[$name])) {
844
		$gateway = $gateways_arr[$name];
845
		if(!is_ipaddr($gateway['monitor']))
846
			return $gateway['gateway'];
847

    
848
		return $gateway['monitor'];
849
        }
850

    
851
        return (false);
852
}
853

    
854
function lookup_gateway_interface_by_name($name) {
855

    
856
        $gateways_arr = return_gateways_array(false, true);
857
	if (!empty($gateways_arr[$name])) {
858
		$interfacegw = $gateway['interface'];
859
		return ($interfacegw);
860
        }
861

    
862
        return (false);
863
}
864

    
865
function get_interface_gateway($interface, &$dynamic = false) {
866
	global $config, $g;
867

    
868
	$gw = NULL;
869

    
870
	$gwcfg = $config['interfaces'][$interface];
871
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
872
		foreach($config['gateways']['gateway_item'] as $gateway) {
873
			if(($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
874
				$gw = $gateway['gateway'];
875
				break;
876
			}
877
		}
878
	}
879

    
880
	// for dynamic interfaces we handle them through the $interface_router file.
881
	if (!is_ipaddrv4($gw) && !is_ipaddrv4($gwcfg['ipaddr'])) {
882
		$realif = get_real_interface($interface);
883
		if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
884
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
885
			$dynamic = true;
886
		}
887
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw"))
888
			$dynamic = "default";
889
			
890
	}
891

    
892
	/* return gateway */
893
	return ($gw);
894
}
895

    
896
function get_interface_gateway_v6($interface, &$dynamic = false) {
897
	global $config, $g;
898

    
899
	$gw = NULL;
900
	$gwcfg = $config['interfaces'][$interface];
901
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
902
		foreach($config['gateways']['gateway_item'] as $gateway) {
903
			if(($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
904
				$gw = $gateway['gateway'];
905
				break;
906
			}
907
		}
908
	}
909

    
910
	// for dynamic interfaces we handle them through the $interface_router file.
911
	if (!is_ipaddrv6($gw) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
912
			$realif = get_real_interface($interface);
913
			if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
914
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
915
				$dynamic = true;
916
			}
917
			if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6"))
918
				$dynamic = "default";
919
			
920
	}
921
	/* return gateway */
922
	return ($gw);
923
}
924

    
925
/* Check a IP address against a gateway IP or name
926
 * to verify it's address family */
927
function validate_address_family($ipaddr, $gwname) {
928
	$v4ip = false;
929
	$v6ip = false;
930
	$v4gw = false;
931
	$v6gw = false;
932

    
933
	if(is_ipaddrv4($ipaddr))
934
		$v4ip = true;
935
	if(is_ipaddrv6($ipaddr))
936
		$v6ip = true;
937
	if(is_ipaddrv4($gwname))
938
		$v4gw = true;
939
	if(is_ipaddrv6($gwname))
940
		$v6gw = true;
941

    
942
	if($v4ip && $v4gw)
943
		return true;
944
	if($v6ip && $v6gw)
945
		return true;
946

    
947
	/* still no match, carry on, lookup gateways */
948
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
949
		$v4gw = true;
950
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
951
		$v6gw = true;
952

    
953
	$gw_array = return_gateways_array();
954
	if(is_array($gw_array[$gwname])) {
955
		switch($gw_array[$gwname]['ipprotocol']) {
956
			case "inet":
957
				$v4gw = true;
958
				break;
959
			case "inet6":
960
				$v6gw = true;
961
				break;
962
		}
963
	}
964

    
965
	if($v4ip && $v4gw)
966
		return true;
967
	if($v6ip && $v6gw)
968
		return true;
969
	
970
	return false;
971
}
972

    
973

    
974
?>
(25-25/66)