Project

General

Profile

Download (30.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:	/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['varrun_path']}/apinger.status");
57
		return;
58
	}
59

    
60
	$apinger_default = return_apinger_defaults();
61
	$apingerconfig = <<<EOD
62

    
63
# pfSense apinger configuration file. Automatically Generated!
64

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

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

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

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

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

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

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

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

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

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

    
120
target default {
121
	## How often the probe should be sent
122
	interval {$apinger_default['interval']}s
123

    
124
	## How many replies should be used to compute average delay
125
	## for controlling "delay" alarms
126
	avg_delay_samples 10
127

    
128
	## How many probes should be used to compute average loss
129
	avg_loss_samples 50
130

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

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

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

    
142
EOD;
143

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

    
156
		/* if the monitor address is already used before, skip */
157
		if(in_array($gateway['monitor'], $monitor_ips))
158
			continue;
159

    
160
		/* Interface ip is needed since apinger will bind a socket to it. */
161
		if (is_ipaddrv4($gateway['gateway'])) {
162
			$gwifip = find_interface_ip($gateway['interface'], true);
163
			if (!is_ipaddrv4($gwifip))
164
				continue; //Skip this target
165
		} else if (is_ipaddrv6($gateway['gateway'])) {
166
			/* link locals really need a different src ip */
167
			if(is_linklocal($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
			if (!is_ipaddrv6($gwifip))
175
				continue; //Skip this target
176
		} else
177
			continue;
178

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

    
233
		$apingercfg .= "	rrd file \"{$g['vardb_path']}/rrd/{$gateway['name']}-quality.rrd\"\n";
234
		$apingercfg .= "}\n";
235
		$apingercfg .= "\n";
236

    
237
		$apingerconfig .= $alarmscfg;
238
		$apingerconfig .= $apingercfg;
239
	}
240
	@file_put_contents("{$g['varetc_path']}/apinger.conf", $apingerconfig);
241
	unset($apingerconfig);
242

    
243
	killbypid("{$g['varrun_path']}/apinger.pid");
244
	if (is_dir("{$g['tmp_path']}"))
245
		chmod("{$g['tmp_path']}", 01777);
246
	if (!is_dir("{$g['vardb_path']}/rrd"))
247
		mkdir("{$g['vardb_path']}/rrd", 0775);
248

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

    
251
	/* start a new apinger process */
252
	@unlink("{$g['varrun_path']}/apinger.status");
253
	sleep(1);
254
	mwexec_bg("/usr/local/sbin/apinger -c {$g['varetc_path']}/apinger.conf");
255
	sleep(1);
256
	sigkillbypid("{$g['varrun_path']}/apinger.pid", "USR1");
257

    
258
	return 0;
259
}
260

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

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

    
270
	$status = array();
271
	foreach($apingerstatus as $line) {
272
		$info = explode("|", $line);
273
		if ($byname == false)
274
			$target = $info[0];
275
		else
276
			$target = $info[2];
277

    
278
		$status[$target] = array();
279
		$status[$target]['monitorip'] = $info[0];
280
		$status[$target]['srcip'] = $info[1];
281
		$status[$target]['name'] = $info[2];
282
		$status[$target]['lastcheck'] = $info[5] ? date('r', $info[5]) : date('r');
283
		$status[$target]['delay'] = empty($info[6]) ? "0ms" : round($info[6], 1) ."ms" ;
284
		$status[$target]['loss'] = empty($info[7]) ? "0.0%" : round($info[7], 1) . "%";
285
		$status[$target]['status'] = trim($info[8]);
286
	}
287

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

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

    
330
/* Return all configured gateways on the system */
331
function return_gateways_array($disabled = false, $localhost = false) {
332
	global $config, $g;
333

    
334
	$gateways_arr = array();
335

    
336
	$found_defaultv4 = 0;
337
	$found_defaultv6 = 0;
338

    
339
	$interfaces_v4 = array();
340
	$interfaces_v6 = array();
341

    
342
	$i = 0;
343
	/* Process/add all the configured gateways. */
344
	if (is_array($config['gateways']['gateway_item'])) {
345
		foreach ($config['gateways']['gateway_item'] as $gateway) {
346
			if (empty($config['interfaces'][$gateway['interface']]))
347
				continue;
348
			$wancfg = $config['interfaces'][$gateway['interface']];
349

    
350
			/* skip disabled interfaces */
351
			if (!isset($wancfg['enable']))
352
				continue;
353

    
354
			/* if the gateway is dynamic and we can find the IPv4, Great! */
355
			if (empty($gateway['gateway']) || $gateway['gateway'] == "dynamic" || $gateway['gateway'] == "dynamic6") {
356
				if ($gateway['ipprotocol'] == "inet") {
357
					/* we know which interfaces is dynamic, this should be made a function */
358
					$gateway['ipprotocol'] = "inet";
359
					$gateway['gateway'] = get_interface_gateway($gateway['interface']);
360
					/* no IP address found, set to dynamic */
361
					if (!is_ipaddrv4($gateway['gateway']))
362
						$gateway['gateway'] = "dynamic";
363
					$gateway['dynamic'] = true;
364
				}
365

    
366
				/* if the gateway is dynamic6 and we can find the IPv6, Great! */
367
				else if ($gateway['ipprotocol'] == "inet6") {
368
					/* we know which interfaces is dynamic, this should be made a function, and for v6 too */
369
					$gateway['ipprotocol'] = "inet6";
370
					$gateway['gateway'] = get_interface_gateway_v6($gateway['interface']);
371
					/* no IPv6 address found, set to dynamic6 */
372
					if (!is_ipaddrv6($gateway['gateway']))
373
						$gateway['gateway'] = "dynamic6";
374
					$gateway['dynamic'] = true;
375
				}
376
			} else {
377
				/* getting this detection right is hard at this point because we still don't
378
				 * store the address family in the gateway item */
379
				if (is_ipaddrv4($gateway['gateway']))
380
					$gateway['ipprotocol'] = "inet";
381
				else if(is_ipaddrv6($gateway['gateway']))
382
					$gateway['ipprotocol'] = "inet6";
383
			}
384

    
385
			if (isset($gateway['monitor_disable']))
386
				$gateway['monitor_disable'] = true;
387
			else if (empty($gateway['monitor']))
388
				$gateway['monitor'] = $gateway['gateway'];
389

    
390
			$gateway['friendlyiface'] = $gateway['interface'];
391

    
392
			/* special treatment for tunnel interfaces */
393
			if ($gateway['ipprotocol'] == "inet6") {
394
				$gateway['interface'] = get_real_interface($gateway['interface'], "inet6");
395
				$interfaces_v6[$gateway['friendlyiface']] = $gateway['friendlyiface'];
396
			} else {
397
				$gateway['interface'] = get_real_interface($gateway['interface']);
398
				$interfaces_v4[$gateway['friendlyiface']] = $gateway['friendlyiface'];
399
			}
400

    
401
			/* entry has a default flag, use it */
402
			if (isset($gateway['defaultgw'])) {
403
				if ($gateway['ipprotocol'] == "inet") {
404
					$gateway['defaultgw'] = true;
405
					$found_defaultv4 = 1;
406
				} else if ($gateway['ipprotocol'] == "inet6") {
407
					$gateway['defaultgw'] = true;
408
					$found_defaultv6 = 1;
409
				}
410
			}
411
			/* include the gateway index as the attribute */
412
			$gateway['attribute'] = $i;
413

    
414
			$gateways_arr[$gateway['name']] = $gateway;
415
			$i++;
416
		}
417
	}
418
	unset($gateway);
419

    
420
	/* Loop through all interfaces with a gateway and add it to a array */
421
	if ($disabled == false)
422
		$iflist = get_configured_interface_with_descr();
423
	else
424
		$iflist = get_configured_interface_with_descr(false, true);
425

    
426
	/* Process/add dynamic v4 gateways. */
427
	foreach($iflist as $ifname => $friendly ) {
428
		if(! interface_has_gateway($ifname))
429
			continue;
430

    
431
		if (empty($config['interfaces'][$ifname]))
432
			continue;
433

    
434
		$ifcfg = &$config['interfaces'][$ifname];
435
		if(!isset($ifcfg['enable']))
436
			continue;
437

    
438
		if(!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr']))
439
			continue;
440

    
441
		if (isset($interfaces_v4[$ifname]))
442
			continue;
443

    
444
		$ctype = "";
445
		switch($ifcfg['ipaddr']) {
446
			case "dhcp":
447
			case "pppoe":
448
			case "pptp":
449
			case "ppp":
450
				$ctype = strtoupper($ifcfg['ipaddr']);
451
				break;
452
			default:
453
				if (substr($ifcfg['if'], 0, 4) ==  "ovpn")
454
					$ctype = "VPNv4";
455
				break;
456
		}
457
		$ctype = "_". strtoupper($ctype);
458

    
459
		$gateway = array();
460
		$gateway['dynamic'] = false;
461
		$gateway['ipprotocol'] = "inet";
462
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
463
		$gateway['interface'] = get_real_interface($ifname);
464
		$gateway['friendlyiface'] = $ifname;
465
		$gateway['name'] = "{$friendly}{$ctype}";
466
		$gateway['attribute'] = "system";
467

    
468
		if (($gateway['dynamic'] === "default") && ($found_defaultv4 == 0)) {
469
			$gateway['defaultgw'] = true;
470
			$gateway['dynamic'] = true;
471
			$found_defaultv4 = 1;
472
		}
473
		/* Loopback dummy for dynamic interfaces without a IP */
474
		if (!is_ipaddrv4($gateway['gateway']) && $gateway['dynamic'] == true)
475
			$gateway['gateway'] = "dynamic";
476

    
477
		/* automatically skip known static and dynamic gateways we have a array entry for */
478
		foreach($gateways_arr as $gateway_item) {
479
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name'])&& ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
480
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
481
					continue 2;
482
		}
483

    
484
		if (is_ipaddrv4($gateway['gateway']))
485
			$gateway['monitor'] = $gateway['gateway'];
486

    
487
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
488
		$gateways_arr[$gateway['name']] = $gateway;
489
	}
490
	unset($gateway);
491

    
492
	/* Process/add dynamic v6 gateways. */
493
	foreach($iflist as $ifname => $friendly ) {
494
		/* If the user has disabled IPv6, they probably don't want any IPv6 gateways. */
495
		if (!isset($config['system']['ipv6allow']))
496
			break;
497

    
498
		if(! interface_has_gatewayv6($ifname))
499
			continue;
500

    
501
		if (empty($config['interfaces'][$ifname]))
502
			continue;
503

    
504
		$ifcfg = &$config['interfaces'][$ifname];
505
		if(!isset($ifcfg['enable']))
506
			continue;
507

    
508
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
509
			continue;
510

    
511
		if(isset($interfaces_v6[$ifname]))
512
			continue;
513

    
514
		$ctype = "";
515
		switch($ifcfg['ipaddrv6']) {
516
			case "slaac":
517
			case "dhcp6":
518
			case "6to4":
519
			case "6rd":
520
				$ctype = strtoupper($ifcfg['ipaddrv6']);
521
				break;
522
			default:
523
				if (substr($ifcfg['if'], 0, 4) ==  "ovpn")
524
					$ctype = "VPNv6";
525
				break;
526
		}
527
		$ctype = "_". strtoupper($ctype);
528

    
529
		$gateway = array();
530
		$gateway['dynamic'] = false;
531
		$gateway['ipprotocol'] = "inet6";
532
		$gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
533
		$gateway['interface'] = get_real_interface($ifname, "inet6");
534
		switch($ifcfg['ipaddrv6']) {
535
			case "6rd":
536
			case "6to4":
537
				$gateway['dynamic'] = "default";
538
				break;
539
		}
540
		$gateway['friendlyiface'] = $ifname;
541
		$gateway['name'] = "{$friendly}{$ctype}";
542
		$gateway['attribute'] = "system";
543

    
544
		if (($gateway['dynamic'] === "default")  && ($found_defaultv6 == 0)) {
545
			$gateway['defaultgw'] = true;
546
			$gateway['dynamic'] = true;
547
			$found_defaultv6 = 1;
548
		}
549

    
550
		/* Loopback dummy for dynamic interfaces without a IP */
551
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
552
			$gateway['gateway'] = "dynamic6";
553

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

    
561
		if (is_ipaddrv6($gateway['gateway']))
562
			$gateway['monitor'] = $gateway['gateway'];
563

    
564
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
565
		$gateways_arr[$gateway['name']] = $gateway;
566
	}
567
	unset($gateway);
568

    
569
	/* FIXME: Should this be enabled.
570
	 * Some interface like wan might be default but have no info recorded
571
	 * the config. */
572
	/* this is a fallback if all else fails and we want to get packets out @smos */
573
	if ($found_defaultv4 == 0 || $found_defaultv6 == 0) {
574
		foreach ($gateways_arr as &$gateway) {
575
			if (($gateway['friendlyiface'] == "wan") && ($found_defaultv4 == 0) && (!isset($gateway['ipprotocol']) || ($gateway['ipprotocol'] == "inet"))) {
576
				if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgw")) {
577
					$gateway['defaultgw'] = true;
578
					$found_defaultv4 = 1;
579
				}
580
			}
581
			if (($gateway['friendlyiface'] == "wan") && ($found_defaultv6 == 0) && ($gateway['ipprotocol'] == "inet6")) {
582
				if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgwv6")) {
583
					$gateway['defaultgw'] = true;
584
					$found_defaultv6 = 1;
585
				}
586
			}
587
		}
588
	}
589

    
590
	if($localhost === true) {
591
		/* attach localhost for Null routes */
592
		$gwlo4 = array();
593
		$gwlo4['name'] = "Null4";
594
		$gwlo4['interface'] = "lo0";
595
		$gwlo4['ipprotocol'] = "inet";
596
		$gwlo4['gateway'] = "127.0.0.1";
597
		$gwlo6 = array();
598
		$gwlo6['name'] = "Null6";
599
		$gwlo6['interface'] = "lo0";
600
		$gwlo6['ipprotocol'] = "inet6";
601
		$gwlo6['gateway'] = "::1";
602
		$gateways_arr['Null4'] = $gwlo4;
603
		$gateways_arr['Null6'] = $gwlo6;
604
	}
605
	return($gateways_arr);
606
}
607

    
608
function fixup_default_gateway($ipprotocol, $gateways_status, $gateways_arr) {
609
	global $config, $g;
610
	/*
611
	 * NOTE: The code below is meant to replace the default gateway when it goes down.
612
	 *	This facilitates services running on pfSense itself and are not handled by a PBR to continue working.
613
	 */
614
	$upgw = "";
615
	$dfltgwdown = false;
616
	$dfltgwfound = false;
617
	foreach ($gateways_arr as $gwname => $gwsttng) {
618
		if (($gwsttng['ipprotocol'] == $ipprotocol) && isset($gwsttng['defaultgw'])) {
619
			$dfltgwfound = true;
620
			$dfltgwname = $gwname;
621
			if (!isset($gwsttng['monitor_disable']) && stristr($gateways_status[$gwname]['status'], "down"))
622
				$dfltgwdown = true;
623
		}
624
		/* Keep a record of the last up gateway */
625
		/* XXX: Blacklist lan for now since it might cause issues to those who have a gateway set for it */
626
		if (empty($upgw) && ($gwsttng['ipprotocol'] == $ipprotocol) && (isset($gwsttng['monitor_disable']) || !stristr($gateways_status[$gwname]['status'], "down")) && $gwsttng[$gwname]['friendlyiface'] != "lan")
627
			$upgw = $gwname;
628
		if ($dfltgwdown == true && !empty($upgw))
629
			break;
630
	}
631
	if ($dfltgwfound == false) {
632
		$gwname = convert_friendly_interface_to_friendly_descr("wan");
633
		if (!empty($gateways_status[$gwname]) && stristr($gateways_status[$gwname]['status'], "down"))
634
			$dfltgwdown = true;
635
	}
636
	if ($dfltgwdown == true && !empty($upgw)) {
637
		if (preg_match("/dynamic/i", $gateways_arr[$upgw]['gateway']))
638
			$gateways_arr[$upgw]['gateway'] = get_interface_gateway($gateways_arr[$upgw]['friendlyiface']);
639
		if (is_ipaddr($gateways_arr[$upgw]['gateway'])) {
640
			log_error("Default gateway down setting {$upgw} as default!");
641
			if(is_ipaddrv6($gateways_arr[$upgw]['gateway'])) {
642
				$inetfamily = "-inet6";
643
			} else {
644
				$inetfamily = "-inet";
645
			}
646
			mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$upgw]['gateway']}");
647
		}
648
	} else {
649
		$defaultgw = trim(`/sbin/route -n get -{$ipprotocol} default | /usr/bin/grep gateway | /usr/bin/sed 's/gateway://g'`, " \n");
650
		if(is_ipaddrv6($gateways_arr[$dfltgwname]['gateway'])) {
651
			$inetfamily = "-inet6";
652
		} else {
653
			$inetfamily = "-inet";
654
		}
655
		if ($defaultgw != $gateways_arr[$dfltgwname]['gateway'])
656
			mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$dfltgwname]['gateway']}");
657
	}
658
}
659

    
660
/*
661
 * Return an array with all gateway groups with name as key
662
 * All gateway groups will be processed before returning the array.
663
 */
664
function return_gateway_groups_array() {
665
	global $config, $g;
666

    
667
	/* fetch the current gateways status */
668
	$gateways_status = return_gateways_status(true);
669
	$gateways_arr = return_gateways_array();
670
	$gateway_groups_array = array();
671

    
672
	if (isset($config['system']['gw_switch_default'])) {
673
		fixup_default_gateway("inet", $gateways_status, $gateways_arr);
674
		fixup_default_gateway("inet6", $gateways_status, $gateways_arr);
675
	}
676
	if (is_array($config['gateways']['gateway_group'])) {
677
		$carplist = get_configured_carp_interface_list();
678
		foreach ($config['gateways']['gateway_group'] as $group) {
679
			/* create array with group gateways members seperated by tier */
680
			$tiers = array();
681
			$backupplan = array();
682
			$gwvip_arr = array();
683
			foreach ($group['item'] as $item) {
684
				list($gwname, $tier, $vipname) = explode("|", $item);
685

    
686
				if (is_ipaddr($carplist[$vipname])) {
687
					if (!is_array($group['name']))
688
						$gwvip_arr[$group['name']] = array();
689
					$gwvip_arr[$group['name']][$gwname] = $vipname;
690
				}
691

    
692
				/* Do it here rather than reiterating again the group in case no member is up. */
693
				if (!is_array($backupplan[$tier]))
694
					$backupplan[$tier] = array();
695
				$backupplan[$tier][] = $gwname;
696

    
697
				/* check if the gateway is available before adding it to the array */
698
				if (is_array($gateways_status[$gwname])) {
699
					$status = $gateways_status[$gwname];
700
					$gwdown = false;
701
					if (stristr($status['status'], "down")) {
702
						$msg = sprintf(gettext("MONITOR: %s is down, removing from routing group {$group['name']}"), $gwname);
703
						$gwdown = true;
704
					} else if (stristr($status['status'], "loss") && strstr($group['trigger'], "loss")) {
705
						/* packet loss */
706
						$msg = sprintf(gettext("MONITOR: %s has packet loss, removing from routing group {$group['name']}"), $gwname);
707
						$gwdown = true;
708
					} else if (stristr($status['status'], "delay") && strstr($group['trigger'] , "latency")) {
709
						/* high latency */
710
						$msg = sprintf(gettext("MONITOR: %s has high latency, removing from routing group {$group['name']}"), $gwname);
711
						$gwdown = true;
712
					}
713
					if ($gwdown == true) {
714
						log_error($msg);
715
						notify_via_growl($msg);
716
						notify_via_smtp($msg);
717
					} else {
718
						/* Online add member */
719
						if (!is_array($tiers[$tier]))
720
							$tiers[$tier] = array();
721
						$tiers[$tier][] = $gwname;
722
					}
723
				} else if (isset($gateways_arr[$gwname]['monitor_disable']))
724
					$tiers[$tier][] = $gwname;
725
			}
726
			$tiers_count = count($tiers);
727
			if ($tiers_count == 0) {
728
				/* Oh dear, we have no members! Engage Plan B */
729
				if (!$g['booting']) {
730
					$msg = gettext("Gateways status could not be determined, considering all as up/active. (Group: {$group['name']})");
731
					log_error($msg);
732
					notify_via_growl($msg);
733
					//notify_via_smtp($msg);
734
				}
735
				$tiers = $backupplan;
736
			}
737
			/* sort the tiers array by the tier key */
738
			ksort($tiers);
739

    
740
			/* we do not really foreach the tiers as we stop after the first tier */
741
			foreach ($tiers as $tieridx => $tier) {
742
				/* process all gateways in this tier */
743
				foreach ($tier as $member) {
744
					/* determine interface gateway */
745
					if (isset($gateways_arr[$member])) {
746
						$gateway = $gateways_arr[$member];
747
						$int = $gateway['interface'];
748
						$gatewayip = "";
749
						if(is_ipaddr($gateway['gateway']))
750
							$gatewayip = $gateway['gateway'];
751
						else if (!empty($int))
752
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
753

    
754
						if (!empty($int) && is_ipaddr($gatewayip)) {
755
							$groupmember = array();
756
							$groupmember['int']  = $int;
757
							$groupmember['gwip']  = $gatewayip;
758
							$groupmember['weight']  = isset($gateway['weight']) ? $gateway['weight'] : 1;
759
							if (is_array($gwvip_arr[$group['name']])&& !empty($gwvip_arr[$group['name']][$gwname]))
760
								$groupmember['vip'] = $gwvip_arr[$group['name']][$gwname];
761
							$gateway_groups_array[$group['name']]['ipprotocol'] = $gateway['ipprotocol'];
762
							$gateway_groups_array[$group['name']][] = $groupmember;
763
						}
764
					}
765
				}
766
				/* we should have the 1st available tier now, exit stage left */
767
				if (count($gateway_groups_array[$group['name']]) > 0)
768
					break;
769
				else
770
					log_error("GATEWAYS: Group {$group['name']} did not have any gateways up on tier {$tieridx}!");
771
			}
772
		}
773
	}
774

    
775
	return ($gateway_groups_array);
776
}
777

    
778
/* Update DHCP WAN Interface ip address in gateway group item */
779
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
780
	global $config, $g;
781
	foreach($config['gateways']['gateway_item'] as & $gw) {
782
		if($gw['interface'] == $interface) {
783
			$current_gw = get_interface_gateway($interface);
784
			if($gw['gateway'] <> $current_gw) {
785
				$gw['gateway'] = $current_gw;
786
				$changed = true;
787
			}
788
		}
789
	}
790
	if($changed && $current_gw)
791
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interfac, $current_gw));
792
}
793

    
794
function lookup_gateway_ip_by_name($name) {
795

    
796
	$gateways_arr = return_gateways_array(false, true);
797
	foreach ($gateways_arr as $gname => $gw) {
798
		if ($gw['name'] === $name || $gname === $name)
799
			return $gw['gateway'];
800
	}
801

    
802
	return false;
803
}
804

    
805
function lookup_gateway_monitor_ip_by_name($name) {
806

    
807
	$gateways_arr = return_gateways_array(false, true);
808
	if (!empty($gateways_arr[$name])) {
809
		$gateway = $gateways_arr[$name];
810
		if(!is_ipaddr($gateway['monitor']))
811
			return $gateway['gateway'];
812

    
813
		return $gateway['monitor'];
814
	}
815

    
816
	return (false);
817
}
818

    
819
function lookup_gateway_interface_by_name($name) {
820

    
821
	$gateways_arr = return_gateways_array(false, true);
822
	if (!empty($gateways_arr[$name])) {
823
		$interfacegw = $gateways_arr[$name]['friendlyiface'];
824
		return ($interfacegw);
825
	}
826

    
827
	return (false);
828
}
829

    
830
function get_interface_gateway($interface, &$dynamic = false) {
831
	global $config, $g;
832

    
833
	$gw = NULL;
834

    
835
	$gwcfg = $config['interfaces'][$interface];
836
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
837
		foreach($config['gateways']['gateway_item'] as $gateway) {
838
			if(($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
839
				$gw = $gateway['gateway'];
840
				break;
841
			}
842
		}
843
	}
844

    
845
	// for dynamic interfaces we handle them through the $interface_router file.
846
	if (!is_ipaddrv4($gw) && !is_ipaddrv4($gwcfg['ipaddr'])) {
847
		$realif = get_real_interface($interface);
848
		if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
849
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
850
			$dynamic = true;
851
		}
852
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw"))
853
			$dynamic = "default";
854

    
855
	}
856

    
857
	/* return gateway */
858
	return ($gw);
859
}
860

    
861
function get_interface_gateway_v6($interface, &$dynamic = false) {
862
	global $config, $g;
863

    
864
	$gw = NULL;
865
	$gwcfg = $config['interfaces'][$interface];
866
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
867
		foreach($config['gateways']['gateway_item'] as $gateway) {
868
			if(($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
869
				$gw = $gateway['gateway'];
870
				break;
871
			}
872
		}
873
	}
874

    
875
	// for dynamic interfaces we handle them through the $interface_router file.
876
	if (!is_ipaddrv6($gw) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
877
			$realif = get_real_interface($interface);
878
			if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
879
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
880
				$dynamic = true;
881
			}
882
			if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6"))
883
				$dynamic = "default";
884

    
885
	}
886
	/* return gateway */
887
	return ($gw);
888
}
889

    
890
/* Check a IP address against a gateway IP or name
891
 * to verify it's address family */
892
function validate_address_family($ipaddr, $gwname) {
893
	$v4ip = false;
894
	$v6ip = false;
895
	$v4gw = false;
896
	$v6gw = false;
897

    
898
	if(is_ipaddrv4($ipaddr))
899
		$v4ip = true;
900
	if(is_ipaddrv6($ipaddr))
901
		$v6ip = true;
902
	if(is_ipaddrv4($gwname))
903
		$v4gw = true;
904
	if(is_ipaddrv6($gwname))
905
		$v6gw = true;
906

    
907
	if($v4ip && $v4gw)
908
		return true;
909
	if($v6ip && $v6gw)
910
		return true;
911

    
912
	/* still no match, carry on, lookup gateways */
913
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
914
		$v4gw = true;
915
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
916
		$v6gw = true;
917

    
918
	$gw_array = return_gateways_array();
919
	if(is_array($gw_array[$gwname])) {
920
		switch($gw_array[$gwname]['ipprotocol']) {
921
			case "inet":
922
				$v4gw = true;
923
				break;
924
			case "inet6":
925
				$v6gw = true;
926
				break;
927
		}
928
	}
929

    
930
	if($v4ip && $v4gw)
931
		return true;
932
	if($v6ip && $v6gw)
933
		return true;
934

    
935
	return false;
936
}
937

    
938
/* check if a interface is part of a gateway group */
939
function interface_gateway_group_member($interface) {
940
	global $config;
941

    
942
	if (is_array($config['gateways']['gateway_group']))
943
		$groups = $config['gateways']['gateway_group'];
944
	else
945
		return false;
946

    
947
	$gateways_arr = return_gateways_array(false, true);
948
	foreach($groups as $group) {
949
		if(is_array($group['item'])) {
950
			foreach($group['item'] as $item) {
951
				$elements = explode("|", $item);
952
				$gwname = $elements[0];
953
				if ($interface == $gateways_arr[$gwname]['interface']) {
954
					unset($gateways_arr);
955
					return true;
956
				}
957
			}
958
		}
959
	}
960
	unset($gateways_arr);
961

    
962
	return false;
963
}
964

    
965
function gateway_is_gwgroup_member($name) {
966
	global $config;
967

    
968
	if (is_array($config['gateways']['gateway_group']))
969
		$groups = $config['gateways']['gateway_group'];
970
	else
971
		return false;
972

    
973
	$members = array();
974
	foreach($groups as $group) {
975
		if (is_array($group['item'])) {
976
			foreach($group['item'] as $item) {
977
				$elements = explode("|", $item);
978
				$gwname = $elements[0];
979
				if ($name == $elements[0])
980
					$members[] = $group['name'];
981
			}
982
		}
983
	}
984

    
985
	return $members;
986
}
987
?>
(24-24/66)