Project

General

Profile

Download (30.8 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[] = monitor_ips;
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

    
256
	return 0;
257
}
258

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

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

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

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

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

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

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

    
332
	$gateways_arr = array();
333

    
334
	$found_defaultv4 = 0;
335
	$found_defaultv6 = 0;
336

    
337
	$interfaces_v4 = array();
338
	$interfaces_v6 = array();
339

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

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

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

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

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

    
388
			$gateway['friendlyiface'] = $gateway['interface'];
389

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

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

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

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

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

    
429
		if (empty($config['interfaces'][$ifname]))
430
			continue;
431

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

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

    
439
		if (isset($interfaces_v4[$ifname]))
440
			continue;
441

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

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

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

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

    
482
		if (is_ipaddrv4($gateway['gateway']))
483
			$gateway['monitor'] = $gateway['gateway'];
484

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

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

    
496
		if(! interface_has_gatewayv6($ifname))
497
			continue;
498

    
499
		if (empty($config['interfaces'][$ifname]))
500
			continue;
501

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

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

    
509
		if(isset($interfaces_v6[$ifname]))
510
			continue;
511

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

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

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

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

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

    
559
		if (is_ipaddrv6($gateway['gateway']))
560
			$gateway['monitor'] = $gateway['gateway'];
561

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

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

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

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

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

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

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

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

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

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

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

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

    
773
	return ($gateway_groups_array);
774
}
775

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

    
792
function lookup_gateway_ip_by_name($name) {
793

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

    
800
	return false;
801
}
802

    
803
function lookup_gateway_monitor_ip_by_name($name) {
804

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

    
811
		return $gateway['monitor'];
812
	}
813

    
814
	return (false);
815
}
816

    
817
function lookup_gateway_interface_by_name($name) {
818

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

    
825
	return (false);
826
}
827

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

    
831
	$gw = NULL;
832

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

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

    
853
	}
854

    
855
	/* return gateway */
856
	return ($gw);
857
}
858

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

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

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

    
883
	}
884
	/* return gateway */
885
	return ($gw);
886
}
887

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

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

    
905
	if($v4ip && $v4gw)
906
		return true;
907
	if($v6ip && $v6gw)
908
		return true;
909

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

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

    
928
	if($v4ip && $v4gw)
929
		return true;
930
	if($v6ip && $v6gw)
931
		return true;
932

    
933
	return false;
934
}
935

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

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

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

    
960
	return false;
961
}
962

    
963
function gateway_is_gwgroup_member($name) {
964
	global $config;
965

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

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

    
983
	return $members;
984
}
985
?>
(24-24/66)