Project

General

Profile

Download (31 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
	if (is_dir("{$g['tmp_path']}"))
244
		chmod("{$g['tmp_path']}", 01777);
245
	if (!is_dir("{$g['vardb_path']}/rrd"))
246
		mkdir("{$g['vardb_path']}/rrd", 0775);
247

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

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

    
261
	return 0;
262
}
263

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

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

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

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

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

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

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

    
337
	$gateways_arr = array();
338

    
339
	$found_defaultv4 = 0;
340
	$found_defaultv6 = 0;
341

    
342
	$interfaces_v4 = array();
343
	$interfaces_v6 = array();
344

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

    
353
			/* skip disabled interfaces */
354
			if (!isset($wancfg['enable']))
355
				continue;
356

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

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

    
388
			if (isset($gateway['monitor_disable']))
389
				$gateway['monitor_disable'] = true;
390
			else if (empty($gateway['monitor']))
391
				$gateway['monitor'] = $gateway['gateway'];
392

    
393
			$gateway['friendlyiface'] = $gateway['interface'];
394

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

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

    
417
			$gateways_arr[$gateway['name']] = $gateway;
418
			$i++;
419
		}
420
	}
421
	unset($gateway);
422

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

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

    
434
		if (empty($config['interfaces'][$ifname]))
435
			continue;
436

    
437
		$ifcfg = &$config['interfaces'][$ifname];
438
		if(!isset($ifcfg['enable']))
439
			continue;
440

    
441
		if(!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr']))
442
			continue;
443

    
444
		if (isset($interfaces_v4[$ifname]))
445
			continue;
446

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

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

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

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

    
487
		if (is_ipaddrv4($gateway['gateway']))
488
			$gateway['monitor'] = $gateway['gateway'];
489

    
490
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
491
		$gateways_arr[$gateway['name']] = $gateway;
492
	}
493
	unset($gateway);
494

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

    
501
		if(! interface_has_gatewayv6($ifname))
502
			continue;
503

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

    
507
		$ifcfg = &$config['interfaces'][$ifname];
508
		if(!isset($ifcfg['enable']))
509
			continue;
510

    
511
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
512
			continue;
513

    
514
		if(isset($interfaces_v6[$ifname]))
515
			continue;
516

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

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

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

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

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

    
564
		if (is_ipaddrv6($gateway['gateway']))
565
			$gateway['monitor'] = $gateway['gateway'];
566

    
567
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
568
		$gateways_arr[$gateway['name']] = $gateway;
569
	}
570
	unset($gateway);
571

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

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

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

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

    
670
	/* fetch the current gateways status */
671
	$gateways_status = return_gateways_status(true);
672
	$gateways_arr = return_gateways_array();
673
	$gateway_groups_array = array();
674

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

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

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

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

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

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

    
778
	return ($gateway_groups_array);
779
}
780

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

    
797
function lookup_gateway_ip_by_name($name) {
798

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

    
805
	return false;
806
}
807

    
808
function lookup_gateway_monitor_ip_by_name($name) {
809

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

    
816
		return $gateway['monitor'];
817
	}
818

    
819
	return (false);
820
}
821

    
822
function lookup_gateway_interface_by_name($name) {
823

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

    
830
	return (false);
831
}
832

    
833
function get_interface_gateway($interface, &$dynamic = false) {
834
	global $config, $g;
835

    
836
	$gw = NULL;
837

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

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

    
858
	}
859

    
860
	/* return gateway */
861
	return ($gw);
862
}
863

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

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

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

    
888
	}
889
	/* return gateway */
890
	return ($gw);
891
}
892

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

    
901
	if(is_ipaddrv4($ipaddr))
902
		$v4ip = true;
903
	if(is_ipaddrv6($ipaddr))
904
		$v6ip = true;
905
	if(is_ipaddrv4($gwname))
906
		$v4gw = true;
907
	if(is_ipaddrv6($gwname))
908
		$v6gw = true;
909

    
910
	if($v4ip && $v4gw)
911
		return true;
912
	if($v6ip && $v6gw)
913
		return true;
914

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

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

    
933
	if($v4ip && $v4gw)
934
		return true;
935
	if($v6ip && $v6gw)
936
		return true;
937

    
938
	return false;
939
}
940

    
941
/* check if a interface is part of a gateway group */
942
function interface_gateway_group_member($interface) {
943
	global $config;
944

    
945
	if (is_array($config['gateways']['gateway_group']))
946
		$groups = $config['gateways']['gateway_group'];
947
	else
948
		return false;
949

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

    
965
	return false;
966
}
967

    
968
function gateway_is_gwgroup_member($name) {
969
	global $config;
970

    
971
	if (is_array($config['gateways']['gateway_group']))
972
		$groups = $config['gateways']['gateway_group'];
973
	else
974
		return false;
975

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

    
988
	return $members;
989
}
990
?>
(24-24/66)