Project

General

Profile

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

    
34
/* Returns an array of default values used for apinger.conf */
35
function return_apinger_defaults() {
36
	return array(
37
		"latencylow" => "200",
38
		"latencyhigh" => "500",
39
		"losslow" => "10",
40
		"losshigh" => "20",
41
		"interval" => "1",
42
		"down" => "10");
43
	}
44

    
45
/*
46
 * Creates monitoring configuration file and
47
 * adds appropriate static routes.
48
 */
49
function setup_gateways_monitor() {
50
	global $config, $g;
51

    
52
	$gateways_arr = return_gateways_array();
53
	if (!is_array($gateways_arr)) {
54
		log_error("No gateways to monitor. Apinger will not be run.");
55
		killbypid("{$g['varrun_path']}/apinger.pid");
56
		@unlink("{$g['tmp_path']}/apinger.status");
57
		return;
58
	}
59

    
60
	$apinger_default = return_apinger_defaults();
61
	$fd = fopen("{$g['varetc_path']}/apinger.conf", "w");
62
	$apingerconfig = <<<EOD
63

    
64
# pfSense apinger configuration file. Automatically Generated!
65

    
66
## User and group the pinger should run as
67
user "root"
68
group "wheel"
69

    
70
## Mailer to use (default: "/usr/lib/sendmail -t")
71
#mailer "/var/qmail/bin/qmail-inject" 
72

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

    
76
## Format of timestamp (%s macro) (default: "%b %d %H:%M:%S")
77
#timestamp_format "%Y%m%d%H%M%S"
78

    
79
status {
80
	## File where the status information should be written to
81
	file "{$g['tmp_path']}/apinger.status"
82
	## Interval between file updates
83
	## when 0 or not set, file is written only when SIGUSR1 is received
84
	interval 5s
85
}
86

    
87
########################################
88
# RRDTool status gathering configuration
89
# Interval between RRD updates
90
rrd interval 60s;
91

    
92
## These parameters can be overridden in a specific alarm configuration
93
alarm default { 
94
	command on "/usr/local/sbin/pfSctl -c 'service reload dyndnsall' -c 'service reload ipsecdns' -c 'service reload openvpn' -c 'filter reload' "
95
	command off "/usr/local/sbin/pfSctl -c 'service reload dyndnsall' -c 'service reload ipsecdns' -c 'service reload openvpn' -c 'filter reload' "
96
	combine 10s
97
}
98

    
99
## "Down" alarm definition. 
100
## This alarm will be fired when target doesn't respond for 30 seconds.
101
alarm down "down" {
102
	time {$apinger_default['down']}s
103
}
104

    
105
## "Delay" alarm definition. 
106
## This alarm will be fired when responses are delayed more than 200ms
107
## it will be canceled, when the delay drops below 100ms
108
alarm delay "delay" {
109
	delay_low {$apinger_default['latencylow']}ms
110
	delay_high {$apinger_default['latencyhigh']}ms
111
}
112

    
113
## "Loss" alarm definition. 
114
## This alarm will be fired when packet loss goes over 20%
115
## it will be canceled, when the loss drops below 10%
116
alarm loss "loss" {
117
	percent_low {$apinger_default['losslow']}
118
	percent_high {$apinger_default['losshigh']}
119
}
120

    
121
target default {
122
	## How often the probe should be sent	
123
	interval {$apinger_default['interval']}s
124
	
125
	## How many replies should be used to compute average delay 
126
	## for controlling "delay" alarms
127
	avg_delay_samples 10
128
	
129
	## How many probes should be used to compute average loss
130
	avg_loss_samples 50
131

    
132
	## The delay (in samples) after which loss is computed
133
	## without this delays larger than interval would be treated as loss
134
	avg_loss_delay_samples 20
135

    
136
	## Names of the alarms that may be generated for the target
137
	alarms "down","delay","loss"
138

    
139
	## Location of the RRD
140
	#rrd file "{$g['vardb_path']}/rrd/apinger-%t.rrd"
141
}
142

    
143
EOD;
144

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

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

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

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

    
252
		$apingerconfig .= $alarmscfg;
253
		$apingerconfig .= $apingercfg;
254
	}
255
	fwrite($fd, $apingerconfig);
256
	fclose($fd);
257
	unset($apingerconfig);
258

    
259
	killbypid("{$g['varrun_path']}/apinger.pid");
260
	if (is_dir("{$g['tmp_path']}"))
261
		chmod("{$g['tmp_path']}", 01777);
262
	if (!is_dir("{$g['vardb_path']}/rrd"))
263
		mkdir("{$g['vardb_path']}/rrd", 0775);
264

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

    
267
	/* start a new apinger process */
268
	@unlink("{$g['tmp_path']}/apinger.status");
269
	sleep(1);
270
	mwexec_bg("/usr/local/sbin/apinger -c {$g['varetc_path']}/apinger.conf");
271

    
272
	return 0;
273
}
274

    
275
/* return the status of the apinger targets as a array */
276
function return_gateways_status($byname = false) {
277
	global $config, $g;
278

    
279
	$apingerstatus = array();
280
	if (file_exists("{$g['tmp_path']}/apinger.status")) {
281
		$apingerstatus = file("{$g['tmp_path']}/apinger.status");
282
	}
283

    
284
	$status = array();
285
	foreach($apingerstatus as $line) {
286
		$info = explode("|", $line);
287
		if ($byname == false)
288
			$target = $info[0];
289
		else
290
			$target = $info[2];
291

    
292
		$status[$target]['monitorip'] = $info[0];
293
		$status[$target]['srcip'] = $info[1];
294
		$status[$target]['name'] = $info[2];
295
		$status[$target]['lastcheck'] = $info[5] ? date('r', $info[5]) : date('r');
296
		$status[$target]['delay'] = empty($info[6]) ? "0ms" : round($info[6], 1) ."ms" ;
297
		$status[$target]['loss'] = empty($info[7]) ? "0.0%" : round($info[7], 1) . "%";
298
		$status[$target]['status'] = trim($info[8]);
299
	}
300

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

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

    
341
/* Return all configured gateways on the system */
342
function return_gateways_array($disabled = false, $localhost = false) {
343
	global $config, $g;
344

    
345
	$gateways_arr = array();
346

    
347
	$found_defaultv4 = 0;
348
	$found_defaultv6 = 0;
349

    
350
	$interfaces_v4 = array();
351
	$interfaces_v6 = array();
352

    
353
	$i = 0;
354
	/* Process/add all the configured gateways. */
355
	if (is_array($config['gateways']['gateway_item'])) {
356
		foreach($config['gateways']['gateway_item'] as $gateway) {
357
			/* skip disabled interfaces */
358
			if(!isset($config['interfaces'][$gateway['interface']]['enable']))
359
				continue;
360

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

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

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

    
424
			if (isset($gateway['monitor_disable']))
425
				$gateway['monitor_disable'] = true;
426
			else if (empty($gateway['monitor']))
427
				$gateway['monitor'] = $gateway['gateway'];
428

    
429
			$gateway['friendlyiface'] = $gateway['interface'];
430

    
431
			/* special treatment for tunnel interfaces */
432
			if($gateway['ipprotocol'] == "inet6") {
433
				switch($wancfg['ipaddrv6']) {
434
					case "6rd":
435
					case "6to4":
436
						$gateway['interface'] = "{$gateway['interface']}_stf";
437
						break;
438
					default:
439
						$gateway['interface'] = get_real_interface($gateway['interface']);
440
						break;
441
				}
442
			}
443
			if($gateway['ipprotocol'] == "inet") {
444
				$gateway['interface'] = get_real_interface($gateway['interface']);
445
			}
446

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

    
479
			/* tack a item on the array to keep track of dynamic interfaces */
480
			if($gateway['ipprotocol'] == "inet")
481
				$interfaces_v4[] = $gateway['friendlyiface'];
482

    
483
			if($gateway['ipprotocol'] == "inet6")
484
				$interfaces_v6[] = $gateway['friendlyiface'];
485

    
486
			$gateways_arr[$gateway['name']] = $gateway;
487
			unset($gateway);
488
			$i++;
489
		}
490
	}
491

    
492
	/* Loop through all interfaces with a gateway and add it to a array */
493
	if ($disabled == false)
494
		$iflist = get_configured_interface_with_descr();
495
	else
496
		$iflist = get_configured_interface_with_descr(false, true);
497

    
498
	/* Process/add dynamic v4 gateways. */
499
	foreach($iflist as $ifname => $friendly ) {
500
		if(! interface_has_gateway($ifname))
501
			continue;
502

    
503
		if (empty($config['interfaces'][$ifname]))
504
			continue;
505

    
506
		$ifcfg = &$config['interfaces'][$ifname];
507
		if(!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr']))
508
			continue;
509

    
510
		if(!isset($ifcfg['enable']))
511
			continue;
512

    
513
		if(in_array($ifname, $interfaces_v4))
514
			continue;
515
			
516
		$ctype = "";
517
		switch($ifcfg['ipaddr']) {
518
			case "dhcp":
519
			case "pppoe":
520
			case "pptp":
521
			case "ppp":
522
				$ctype = strtoupper($ifcfg['ipaddr']);
523
				break;
524
			default:
525
				if (substr($ifcfg['if'], 0, 4) ==  "ovpn")
526
					$ctype = "VPNv4";
527
				break;
528
		}
529
		$ctype = "_". strtoupper($ctype);
530

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

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

    
556
		if (is_ipaddrv4($gateway['gateway']))
557
			$gateway['monitor'] = $gateway['gateway'];
558

    
559
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
560
		$gateways_arr[$gateway['name']] = $gateway;
561
		unset($gateway);
562
	}
563

    
564
	/* Process/add dynamic v6 gateways. */
565
	foreach($iflist as $ifname => $friendly ) {
566
		/* If the user has disabled IPv6, they probably don't want any IPv6 gateways. */
567
		if (!isset($config['system']['ipv6allow']))
568
			break;
569

    
570
		if(! interface_has_gatewayv6($ifname))
571
			continue;
572

    
573
		if (empty($config['interfaces'][$ifname]))
574
			continue;
575

    
576
		$ifcfg = &$config['interfaces'][$ifname];
577
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
578
			continue;
579
			
580
		if(!isset($ifcfg['enable']))
581
			continue;
582

    
583
		if(in_array($ifname, $interfaces_v6))
584
			continue;
585

    
586
		$ctype = "";
587
		switch($ifcfg['ipaddrv6']) {
588
			case "slaac":
589
			case "dhcp6":
590
			case "6to4":
591
			case "6rd":
592
				$ctype = strtoupper($ifcfg['ipaddrv6']);
593
				break;
594
			default:
595
				if (substr($ifcfg['if'], 0, 4) ==  "ovpn")
596
					$ctype = "VPNv6";
597
				break;
598
		}
599
		$ctype = "_". strtoupper($ctype);
600

    
601
		$gateway = array();
602
		$gateway['dynamic'] = false;
603
		$gateway['ipprotocol'] = "inet6";
604
		$gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
605
		switch($ifcfg['ipaddrv6']) {
606
			case "6to4":
607
				$gateway['interface'] = "{$ifname}_stf";
608
				$gateway['dynamic'] = "default";
609
				break;
610
			case "6rd":
611
				$gateway['interface'] = "{$ifname}_stf";
612
				$gateway['dynamic'] = "default";
613
				break;
614
			default:
615
				$gateway['interface'] = get_real_interface($ifname);
616
				break;
617
		}
618
		$gateway['friendlyiface'] = $ifname;
619
		$gateway['name'] = "{$friendly}{$ctype}";
620
		$gateway['attribute'] = "system";
621
	
622
		if (($gateway['dynamic'] === "default")  && ($found_defaultv6 == 0)) {
623
			$gateway['defaultgw'] = true;
624
			$gateway['dynamic'] = true;
625
			$found_defaultv6 = 1;
626
		}
627

    
628
		/* Loopback dummy for dynamic interfaces without a IP */
629
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
630
			$gateway['gateway'] = "dynamic6";
631

    
632
		/* automatically skip known static and dynamic gateways we have a array entry for */
633
		foreach($gateways_arr as $gateway_item) {
634
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
635
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
636
					continue 2;
637
		}
638

    
639
		if (is_ipaddrv6($gateway['gateway']))
640
			$gateway['monitor'] = $gateway['gateway'];
641

    
642
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
643
		$gateways_arr[$gateway['name']] = $gateway;
644
		unset($gateway);
645
	}
646

    
647
	if($localhost === true) {
648
		/* attach localhost for Null routes */
649
		$gwlo4 = array();
650
		$gwlo4['name'] = "Null4";
651
		$gwlo4['interface'] = "lo0";
652
		$gwlo4['ipprotocol'] = "inet";
653
		$gwlo4['gateway'] = "127.0.0.1";
654
		$gwlo6 = array();
655
		$gwlo6['name'] = "Null6";
656
		$gwlo6['interface'] = "lo0";
657
		$gwlo6['ipprotocol'] = "inet6";
658
		$gwlo6['gateway'] = "::1";
659
		$gateways_arr['Null4'] = $gwlo4;
660
		$gateways_arr['Null6'] = $gwlo6;
661
	}
662
	return($gateways_arr);
663
}
664

    
665
function fixup_default_gateway($ipprotocol, $gateways_status, $gateways_arr) {
666
	global $config, $g;
667
	/*
668
	 * NOTE: The code below is meant to replace the default gateway when it goes down.
669
	 *	This facilitates services running on pfSense itself and are not handled by a PBR to continue working.
670
	 */
671
	$upgw = "";
672
	$dfltgwdown = false;
673
	$dfltgwfound = false;
674
	foreach ($gateways_arr as $gwname => $gwsttng) {
675
		if (($gwsttng['ipprotocol'] == $ipprotocol) && isset($gwsttng['defaultgw'])) {
676
			$dfltgwfound = true;
677
			$dfltgwname = $gwname;
678
			if (!isset($gwsttng['monitor_disable']) && stristr($gateways_status[$gwname]['status'], "down"))
679
				$dfltgwdown = true;
680
		}
681
		/* Keep a record of the last up gateway */
682
		/* XXX: Blacklist lan for now since it might cause issues to those who have a gateway set for it */
683
		if (empty($upgw) && ($gwsttng['ipprotocol'] == $ipprotocol) && (isset($gwsttng['monitor_disable']) || !stristr($gateways_status[$gwname]['status'], "down")) && $gwsttng[$gwname]['friendlyiface'] != "lan")
684
			$upgw = $gwname;
685
		if ($dfltgwdown == true && !empty($upgw))
686
			break;
687
	}
688
	if ($dfltgwfound == false) {
689
		$gwname = convert_friendly_interface_to_friendly_descr("wan");
690
		if (!empty($gateways_status[$gwname]) && stristr($gateways_status[$gwname]['status'], "down"))
691
			$dfltgwdown = true;
692
	}
693
	if ($dfltgwdown == true && !empty($upgw)) {
694
		if (preg_match("/dynamic/i", $gateways_arr[$upgw]['gateway']))
695
			$gateways_arr[$upgw]['gateway'] = get_interface_gateway($gateways_arr[$upgw]['friendlyiface']);
696
		if (is_ipaddr($gateways_arr[$upgw]['gateway'])) {
697
			log_error("Default gateway down setting {$upgw} as default!");
698
			if(is_ipaddrv6($gateways_arr[$upgw]['gateway'])) {
699
				$inetfamily = "-inet6";
700
			} else {
701
				$inetfamily = "-inet";
702
			}
703
			mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$upgw]['gateway']}");
704
		}
705
	} else {
706
		$defaultgw = trim(`/sbin/route -n get -{$ipprotocol} default | /usr/bin/grep gateway | /usr/bin/sed 's/gateway://g'`, " \n");
707
		if(is_ipaddrv6($gateways_arr[$dfltgwname]['gateway'])) {
708
			$inetfamily = "-inet6";
709
		} else {
710
			$inetfamily = "-inet";
711
		}
712
		if ($defaultgw != $gateways_arr[$dfltgwname]['gateway'])
713
			mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$dfltgwname]['gateway']}");
714
	}
715
}
716

    
717
/*
718
 * Return an array with all gateway groups with name as key
719
 * All gateway groups will be processed before returning the array.
720
 */
721
function return_gateway_groups_array() {
722
	global $config, $g;
723

    
724
	/* fetch the current gateways status */
725
	$gateways_status = return_gateways_status(true);
726
	$gateways_arr = return_gateways_array();
727
	$gateway_groups_array = array();
728
	$carplist = get_configured_carp_interface_list();
729

    
730
	if (isset($config['system']['gw_switch_default'])) {
731
		fixup_default_gateway("inet", $gateways_status, $gateways_arr);
732
		fixup_default_gateway("inet6", $gateways_status, $gateways_arr);
733
	}
734
	if (is_array($config['gateways']['gateway_group'])) {
735
		foreach($config['gateways']['gateway_group'] as $group) {
736
			/* create array with group gateways members seperated by tier */
737
			$tiers = array();
738
			$backupplan = array();
739
			foreach($group['item'] as $item) {
740
				$itemsplit = explode("|", $item);
741
				$tier = $itemsplit[1];
742
				$gwname = $itemsplit[0];
743
				$vipname = $itemsplit[2];
744
				if(is_ipaddr($carplist[$vipname]))
745
					$gwvip_arr[$group['name']][$gwname] = $vipname;
746

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

    
750
				/* check if the gateway is available before adding it to the array */
751
				if (is_array($gateways_status[$gwname])) {
752
					$status = $gateways_status[$gwname];
753
					$gwdown = false;
754
					if (stristr($status['status'], "down")) {
755
						$msg = sprintf(gettext("MONITOR: %s is down, removing from routing group {$group['name']}"), $gwname);
756
						$gwdown = true;
757
					} else if (stristr($status['status'], "loss") && strstr($group['trigger'], "loss")) {
758
						/* packet loss */
759
						$msg = sprintf(gettext("MONITOR: %s has packet loss, removing from routing group {$group['name']}"), $gwname);
760
						$gwdown = true;
761
					} else if (stristr($status['status'], "delay") && strstr($group['trigger'] , "latency")) {
762
						/* high latency */
763
						$msg = sprintf(gettext("MONITOR: %s has high latency, removing from routing group {$group['name']}"), $gwname);
764
						$gwdown = true;
765
					}
766
					if ($gwdown == true) {
767
						log_error($msg);
768
						notify_via_growl($msg);
769
						notify_via_smtp($msg);
770
					} else {
771
						/* Online add member */
772
						$tiers[$tier][] = $gwname;
773
					}
774
				} else if (isset($gateways_arr[$gwname]['monitor_disable']))
775
					$tiers[$tier][] = $gwname;
776
			}
777
			$tiers_count = count($tiers);
778
			if($tiers_count == 0) {
779
				/* Oh dear, we have no members! Engage Plan B */
780
				if (!$g['booting']) {
781
					$msg = gettext("Gateways status could not be determined, considering all as up/active. (Group: {$group['name']})");
782
					log_error($msg);
783
					notify_via_growl($msg);
784
					//notify_via_smtp($msg);
785
				}
786
				$tiers = $backupplan;
787
			}
788
			/* sort the tiers array by the tier key */
789
			ksort($tiers);
790

    
791
			/* we do not really foreach the tiers as we stop after the first tier */
792
			foreach($tiers as $tier) {
793
				/* process all gateways in this tier */
794
				foreach($tier as $member) {
795
					/* determine interface gateway */
796
					if (isset($gateways_arr[$member])) {
797
						$gateway = $gateways_arr[$member];
798
						$int = $gateway['interface'];
799
						$gatewayip = "";
800
						if(is_ipaddr($gateway['gateway'])) 
801
							$gatewayip = $gateway['gateway'];
802
						else if ($int <> "")
803
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
804
					
805
						if (($int <> "") && is_ipaddr($gatewayip)) {
806
							$groupmember = array();
807
							$groupmember['int']  = $int;
808
							$groupmember['gwip']  = $gatewayip;
809
							$groupmember['weight']  = isset($gateway['weight']) ? $gateway['weight'] : 1;
810
							if($gwvip_arr[$group['name']][$gwname] <> "")
811
								$groupmember['vip'] = $gwvip_arr[$group['name']][$gwname];
812
							$gateway_groups_array[$group['name']]['ipprotocol'] = $gateway['ipprotocol'];
813
							$gateway_groups_array[$group['name']][] = $groupmember;
814
						}
815
					}
816
				}
817
				/* we should have the 1st available tier now, exit stage left */
818
				if(is_array($gateway_groups_array[$group['name']]))
819
					break;
820
				else
821
					log_error("GATEWAYS: We did not find the first tier of the gateway group {$group['name']}! That's odd.");
822
			}
823
		}
824
	}
825
	return ($gateway_groups_array);
826
}
827

    
828
/* Update DHCP WAN Interface ip address in gateway group item */
829
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
830
	global $config, $g;
831
	foreach($config['gateways']['gateway_item'] as & $gw) {	
832
		if($gw['interface'] == $interface) {
833
			$current_gw = get_interface_gateway($interface);
834
			if($gw['gateway'] <> $current_gw) {
835
				$gw['gateway'] = $current_gw;
836
				$changed = true;
837
			}
838
		}
839
	}
840
	if($changed && $current_gw)
841
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interfac, $current_gw));
842
}
843

    
844
function lookup_gateway_ip_by_name($name) {
845

    
846
	$gateways_arr = return_gateways_array(false, true);
847
        foreach ($gateways_arr as $gname => $gw) {
848
                if ($gw['name'] == $name || $gname == $name)
849
                        return $gw['gateway'];
850
        }
851

    
852
	return false;
853
}
854

    
855
function lookup_gateway_monitor_ip_by_name($name) {
856

    
857
        $gateways_arr = return_gateways_array(false, true);
858
	if (!empty($gateways_arr[$name])) {
859
		$gateway = $gateways_arr[$name];
860
		if(!is_ipaddr($gateway['monitor']))
861
			return $gateway['gateway'];
862

    
863
		return $gateway['monitor'];
864
        }
865

    
866
        return (false);
867
}
868

    
869
function lookup_gateway_interface_by_name($name) {
870

    
871
        $gateways_arr = return_gateways_array(false, true);
872
	if (!empty($gateways_arr[$name])) {
873
		$interfacegw = $gateways_arr[$name]['interface'];
874
		return ($interfacegw);
875
        }
876

    
877
        return (false);
878
}
879

    
880
function get_interface_gateway($interface, &$dynamic = false) {
881
	global $config, $g;
882

    
883
	$gw = NULL;
884

    
885
	$gwcfg = $config['interfaces'][$interface];
886
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
887
		foreach($config['gateways']['gateway_item'] as $gateway) {
888
			if(($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
889
				$gw = $gateway['gateway'];
890
				break;
891
			}
892
		}
893
	}
894

    
895
	// for dynamic interfaces we handle them through the $interface_router file.
896
	if (!is_ipaddrv4($gw) && !is_ipaddrv4($gwcfg['ipaddr'])) {
897
		$realif = get_real_interface($interface);
898
		if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
899
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
900
			$dynamic = true;
901
		}
902
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw"))
903
			$dynamic = "default";
904
			
905
	}
906

    
907
	/* return gateway */
908
	return ($gw);
909
}
910

    
911
function get_interface_gateway_v6($interface, &$dynamic = false) {
912
	global $config, $g;
913

    
914
	$gw = NULL;
915
	$gwcfg = $config['interfaces'][$interface];
916
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
917
		foreach($config['gateways']['gateway_item'] as $gateway) {
918
			if(($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
919
				$gw = $gateway['gateway'];
920
				break;
921
			}
922
		}
923
	}
924

    
925
	// for dynamic interfaces we handle them through the $interface_router file.
926
	if (!is_ipaddrv6($gw) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
927
			$realif = get_real_interface($interface);
928
			if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
929
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
930
				$dynamic = true;
931
			}
932
			if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6"))
933
				$dynamic = "default";
934
			
935
	}
936
	/* return gateway */
937
	return ($gw);
938
}
939

    
940
/* Check a IP address against a gateway IP or name
941
 * to verify it's address family */
942
function validate_address_family($ipaddr, $gwname) {
943
	$v4ip = false;
944
	$v6ip = false;
945
	$v4gw = false;
946
	$v6gw = false;
947

    
948
	if(is_ipaddrv4($ipaddr))
949
		$v4ip = true;
950
	if(is_ipaddrv6($ipaddr))
951
		$v6ip = true;
952
	if(is_ipaddrv4($gwname))
953
		$v4gw = true;
954
	if(is_ipaddrv6($gwname))
955
		$v6gw = true;
956

    
957
	if($v4ip && $v4gw)
958
		return true;
959
	if($v6ip && $v6gw)
960
		return true;
961

    
962
	/* still no match, carry on, lookup gateways */
963
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
964
		$v4gw = true;
965
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
966
		$v6gw = true;
967

    
968
	$gw_array = return_gateways_array();
969
	if(is_array($gw_array[$gwname])) {
970
		switch($gw_array[$gwname]['ipprotocol']) {
971
			case "inet":
972
				$v4gw = true;
973
				break;
974
			case "inet6":
975
				$v6gw = true;
976
				break;
977
		}
978
	}
979

    
980
	if($v4ip && $v4gw)
981
		return true;
982
	if($v6ip && $v6gw)
983
		return true;
984
	
985
	return false;
986
}
987

    
988
/* check if a interface is part of a gateway group */
989
function interface_gateway_group_member($interface) {
990
	global $config;
991
	$realif = get_real_interface($interface);
992
	if(is_array($config['gateways']['gateway_group']))
993
		$groups = $config['gateways']['gateway_group'];
994
	else
995
		return false;
996

    
997
	foreach($groups as $group) {
998
		if(is_array($group['item'])) {
999
			foreach($group['item'] as $item) {
1000
				$elements = explode("|", $item);
1001
				$gwname = $elements[0];
1002
				$gwif = get_real_interface(lookup_gateway_interface_by_name($gwname));
1003
				if($gwif == $realif)
1004
					return true;
1005
			}
1006
		}
1007
	}
1008
	return false;
1009
}
1010

    
1011
?>
(24-24/66)