Project

General

Profile

Download (31.9 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)) {
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)) {
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(! interface_has_gatewayv6($ifname))
567
			continue;
568

    
569
		if (empty($config['interfaces'][$ifname]))
570
			continue;
571

    
572
		$ifcfg = &$config['interfaces'][$ifname];
573
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
574
			continue;
575
			
576
		if(!isset($ifcfg['enable']))
577
			continue;
578

    
579
		if(in_array($ifname, $interfaces_v6))
580
			continue;
581

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

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

    
624
		/* Loopback dummy for dynamic interfaces without a IP */
625
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
626
			$gateway['gateway'] = "dynamic6";
627

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

    
635
		if (is_ipaddrv6($gateway['gateway']))
636
			$gateway['monitor'] = $gateway['gateway'];
637

    
638
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
639
		$gateways_arr[$gateway['name']] = $gateway;
640
		unset($gateway);
641
	}
642

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

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

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

    
720
	/* fetch the current gateways status */
721
	$gateways_status = return_gateways_status(true);
722
	$gateways_arr = return_gateways_array();
723
	$gateway_groups_array = array();
724
	$carplist = get_configured_carp_interface_list();
725

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

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

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

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

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

    
840
function lookup_gateway_ip_by_name($name) {
841

    
842
	$gateways_arr = return_gateways_array(false, true);
843
        foreach ($gateways_arr as $gname => $gw) {
844
                if ($gw['name'] == $name || $gname == $name)
845
                        return $gw['gateway'];
846
        }
847

    
848
	return false;
849
}
850

    
851
function lookup_gateway_monitor_ip_by_name($name) {
852

    
853
        $gateways_arr = return_gateways_array(false, true);
854
	if (!empty($gateways_arr[$name])) {
855
		$gateway = $gateways_arr[$name];
856
		if(!is_ipaddr($gateway['monitor']))
857
			return $gateway['gateway'];
858

    
859
		return $gateway['monitor'];
860
        }
861

    
862
        return (false);
863
}
864

    
865
function lookup_gateway_interface_by_name($name) {
866

    
867
        $gateways_arr = return_gateways_array(false, true);
868
	if (!empty($gateways_arr[$name])) {
869
		$interfacegw = $gateways_arr[$name]['interface'];
870
		return ($interfacegw);
871
        }
872

    
873
        return (false);
874
}
875

    
876
function get_interface_gateway($interface, &$dynamic = false) {
877
	global $config, $g;
878

    
879
	$gw = NULL;
880

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

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

    
903
	/* return gateway */
904
	return ($gw);
905
}
906

    
907
function get_interface_gateway_v6($interface, &$dynamic = false) {
908
	global $config, $g;
909

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

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

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

    
944
	if(is_ipaddrv4($ipaddr))
945
		$v4ip = true;
946
	if(is_ipaddrv6($ipaddr))
947
		$v6ip = true;
948
	if(is_ipaddrv4($gwname))
949
		$v4gw = true;
950
	if(is_ipaddrv6($gwname))
951
		$v6gw = true;
952

    
953
	if($v4ip && $v4gw)
954
		return true;
955
	if($v6ip && $v6gw)
956
		return true;
957

    
958
	/* still no match, carry on, lookup gateways */
959
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
960
		$v4gw = true;
961
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
962
		$v6gw = true;
963

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

    
976
	if($v4ip && $v4gw)
977
		return true;
978
	if($v6ip && $v6gw)
979
		return true;
980
	
981
	return false;
982
}
983

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

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

    
1007
?>
(24-24/67)