Project

General

Profile

Download (32.4 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

    
166
			/*
167
			 * If the gateway is the same as the monitor we do not add a
168
			 * route as this will break the routing table.
169
			 * Add static routes for each gateway with their monitor IP
170
			 * not strictly necessary but is a added level of protection.
171
			 */
172
			if (is_ipaddrv4($gateway['gateway']) && $gateway['monitor'] != $gateway['gateway']) {
173
				log_error("Removing static route for monitor {$gateway['monitor']} and adding a new route through {$gateway['gateway']}");
174
				mwexec("/sbin/route change -host " . escapeshellarg($gateway['monitor']) .
175
					" " . escapeshellarg($gateway['gateway']), true);
176
			}
177
		} else if (is_ipaddrv6($gateway['gateway'])) {
178
			/* link locals really need a different src ip */
179
			if(is_linklocal($gateway['gateway'])) {
180
				$gwifip = find_interface_ipv6_ll($gateway['interface'], true);
181
			} else {
182
				$gwifip = find_interface_ipv6($gateway['interface'], true);
183
			}
184
			if (is_linklocal($gateway['monitor']) && !strstr($gateway['monitor'], '%'))
185
				$gateway['monitor'] .= "%{$gateway['interface']}";
186
			if (!is_ipaddrv6($gwifip))
187
				continue; //Skip this target
188

    
189
			/*
190
			 * If the gateway is the same as the monitor we do not add a
191
			 * route as this will break the routing table.
192
			 * Add static routes for each gateway with their monitor IP
193
			 * not strictly necessary but is a added level of protection.
194
			 */
195
			if (is_ipaddrv6($gateway['gateway']) && $gateway['monitor'] != $gateway['gateway']) {
196
				log_error("Removing static route for monitor {$gateway['monitor']} and adding a new route through {$gateway['gateway']}");
197
				mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gateway['monitor']) .
198
					" " . escapeshellarg($gateway['gateway']), true);
199
			}
200
		} else
201
			continue;
202

    
203
		$monitor_ips[] = $gateway['monitor'];
204
		$apingercfg = "target \"{$gateway['monitor']}\" {\n";
205
		$apingercfg .= "	description \"{$name}\"\n";
206
		$apingercfg .= "	srcip \"{$gwifip}\"\n";
207
		if (!empty($gateway['interval']) && intval($gateway['interval']) > 1)
208
			$apingercfg .= "	interval " . intval($gateway['interval']) . "s\n";
209
		$alarms = "";
210
		$alarmscfg = "";
211
		$override = false;
212
		if (!empty($gateway['losslow'])) {
213
			$alarmscfg .= "alarm loss \"{$name}loss\" {\n";
214
			$alarmscfg .= "\tpercent_low {$gateway['losslow']}\n";
215
			$alarmscfg .= "\tpercent_high {$gateway['losshigh']}\n";
216
			$alarmscfg .= "}\n";
217
			$alarms .= "\"{$name}loss\"";
218
			$override = true;
219
		} else {
220
			if ($override == true)
221
				$alarms .= ",";
222
			$alarms .= "\"loss\"";
223
			$override = true;
224
		}
225
		if (!empty($gateway['latencylow'])) {
226
			$alarmscfg .= "alarm delay \"{$name}delay\" {\n";
227
			$alarmscfg .= "\tdelay_low {$gateway['latencylow']}ms\n";
228
			$alarmscfg .= "\tdelay_high {$gateway['latencyhigh']}ms\n";
229
			$alarmscfg .= "}\n";
230
			if ($override == true)
231
				$alarms .= ",";
232
			$alarms .= "\"{$name}delay\"";
233
			$override = true;
234
		} else {
235
			if ($override == true)
236
				$alarms .= ",";
237
			$alarms .= "\"delay\"";
238
			$override = true;
239
		}
240
		if (!empty($gateway['down'])) {
241
			$alarmscfg .= "alarm down \"{$name}down\" {\n";
242
			$alarmscfg .= "\ttime {$gateway['down']}s\n";
243
			$alarmscfg .= "}\n";
244
			if ($override == true)
245
				$alarms .= ",";
246
			$alarms .= "\"{$name}down\"";
247
			$override = true;
248
		} else {
249
			if ($override == true)
250
				$alarms .= ",";
251
			$alarms .= "\"down\"";
252
			$override = true;
253
		}
254
		if ($override == true)
255
			$apingercfg .= "\talarms override {$alarms};\n";
256

    
257
		$apingercfg .= "	rrd file \"{$g['vardb_path']}/rrd/{$gateway['name']}-quality.rrd\"\n";
258
		$apingercfg .= "}\n";
259
		$apingercfg .= "\n";
260

    
261
		$apingerconfig .= $alarmscfg;
262
		$apingerconfig .= $apingercfg;
263
	}
264
	@file_put_contents("{$g['varetc_path']}/apinger.conf", $apingerconfig);
265
	unset($apingerconfig);
266

    
267
	if (is_dir("{$g['tmp_path']}"))
268
		chmod("{$g['tmp_path']}", 01777);
269
	if (!is_dir("{$g['vardb_path']}/rrd"))
270
		mkdir("{$g['vardb_path']}/rrd", 0775);
271

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

    
274
	if (isvalidpid("{$g['varrun_path']}/apinger.pid"))
275
		sigkillbypid("{$g['varrun_path']}/apinger.pid", "HUP");
276
	else {
277
		/* start a new apinger process */
278
		@unlink("{$g['varrun_path']}/apinger.status");
279
		sleep(1);
280
		mwexec_bg("/usr/local/sbin/apinger -c {$g['varetc_path']}/apinger.conf");
281
		sleep(1);
282
		sigkillbypid("{$g['varrun_path']}/apinger.pid", "USR1");
283
	}
284

    
285
	return 0;
286
}
287

    
288
/* return the status of the apinger targets as a array */
289
function return_gateways_status($byname = false) {
290
	global $config, $g;
291

    
292
	$apingerstatus = array();
293
	/* Always get the latest status from apinger */
294
	if (file_exists("{$g['varrun_path']}/apinger.pid"))
295
                sigkillbypid("{$g['varrun_path']}/apinger.pid", "USR1");
296
	if (file_exists("{$g['varrun_path']}/apinger.status")) {
297
		$apingerstatus = file("{$g['varrun_path']}/apinger.status");
298
	} else
299
		$apingerstatus = array();
300

    
301
	$status = array();
302
	foreach($apingerstatus as $line) {
303
		$info = explode("|", $line);
304
		if ($byname == false)
305
			$target = $info[0];
306
		else
307
			$target = $info[2];
308

    
309
		$status[$target] = array();
310
		$status[$target]['monitorip'] = $info[0];
311
		$status[$target]['srcip'] = $info[1];
312
		$status[$target]['name'] = $info[2];
313
		$status[$target]['lastcheck'] = $info[5] ? date('r', $info[5]) : date('r');
314
		$status[$target]['delay'] = empty($info[6]) ? "0ms" : round($info[6], 1) ."ms" ;
315
		$status[$target]['loss'] = empty($info[7]) ? "0.0%" : round($info[7], 1) . "%";
316
		$status[$target]['status'] = trim($info[8]);
317
	}
318

    
319
	/* tack on any gateways that have monitoring disabled
320
	 * or are down, which could cause gateway groups to fail */
321
	$gateways_arr = return_gateways_array();
322
	foreach($gateways_arr as $gwitem) {
323
		if(!isset($gwitem['monitor_disable']))
324
			continue;
325
		if(!is_ipaddr($gwitem['monitorip'])) {
326
			$realif = $gwitem['interface'];
327
			$tgtip = get_interface_gateway($realif);
328
			if (!is_ipaddr($tgtip))
329
				$tgtip = "none";
330
			$srcip = find_interface_ip($realif);
331
		} else {
332
			$tgtip = $gwitem['monitorip'];
333
			$srcip = find_interface_ip($realif);
334
		}
335
		if($byname == true)
336
			$target = $gwitem['name'];
337
		else
338
			$target = $tgtip;
339

    
340
		/* failsafe for down interfaces */
341
		if($target == "none") {
342
			$target = $gwitem['name'];
343
			$status[$target]['name'] = $gwitem['name'];
344
			$status[$target]['lastcheck'] = date('r');
345
			$status[$target]['delay'] = "0.0ms";
346
			$status[$target]['loss'] = "100.0%";
347
			$status[$target]['status'] = "down";
348
		} else {
349
			$status[$target]['monitorip'] = $tgtip;
350
			$status[$target]['srcip'] = $srcip;
351
			$status[$target]['name'] = $gwitem['name'];
352
			$status[$target]['lastcheck'] = date('r');
353
			$status[$target]['delay'] = "0.0ms";
354
			$status[$target]['loss'] = "0.0%";
355
			$status[$target]['status'] = "none";
356
		}
357
	}
358
	return($status);
359
}
360

    
361
/* Return all configured gateways on the system */
362
function return_gateways_array($disabled = false, $localhost = false) {
363
	global $config, $g;
364

    
365
	$gateways_arr = array();
366

    
367
	$found_defaultv4 = 0;
368
	$found_defaultv6 = 0;
369

    
370
	$interfaces_v4 = array();
371
	$interfaces_v6 = array();
372

    
373
	$i = 0;
374
	/* Process/add all the configured gateways. */
375
	if (is_array($config['gateways']['gateway_item'])) {
376
		foreach ($config['gateways']['gateway_item'] as $gateway) {
377
			if (empty($config['interfaces'][$gateway['interface']]))
378
				continue;
379
			$wancfg = $config['interfaces'][$gateway['interface']];
380

    
381
			/* skip disabled interfaces */
382
			if (!isset($wancfg['enable']))
383
				continue;
384

    
385
			/* if the gateway is dynamic and we can find the IPv4, Great! */
386
			if (empty($gateway['gateway']) || $gateway['gateway'] == "dynamic" || $gateway['gateway'] == "dynamic6") {
387
				if ($gateway['ipprotocol'] == "inet") {
388
					/* we know which interfaces is dynamic, this should be made a function */
389
					$gateway['ipprotocol'] = "inet";
390
					$gateway['gateway'] = get_interface_gateway($gateway['interface']);
391
					/* no IP address found, set to dynamic */
392
					if (!is_ipaddrv4($gateway['gateway']))
393
						$gateway['gateway'] = "dynamic";
394
					$gateway['dynamic'] = true;
395
				}
396

    
397
				/* if the gateway is dynamic6 and we can find the IPv6, Great! */
398
				else if ($gateway['ipprotocol'] == "inet6") {
399
					/* we know which interfaces is dynamic, this should be made a function, and for v6 too */
400
					$gateway['ipprotocol'] = "inet6";
401
					$gateway['gateway'] = get_interface_gateway_v6($gateway['interface']);
402
					/* no IPv6 address found, set to dynamic6 */
403
					if (!is_ipaddrv6($gateway['gateway']))
404
						$gateway['gateway'] = "dynamic6";
405
					$gateway['dynamic'] = true;
406
				}
407
			} else {
408
				/* getting this detection right is hard at this point because we still don't
409
				 * store the address family in the gateway item */
410
				if (is_ipaddrv4($gateway['gateway']))
411
					$gateway['ipprotocol'] = "inet";
412
				else if(is_ipaddrv6($gateway['gateway']))
413
					$gateway['ipprotocol'] = "inet6";
414
			}
415

    
416
			if (isset($gateway['monitor_disable']))
417
				$gateway['monitor_disable'] = true;
418
			else if (empty($gateway['monitor']))
419
				$gateway['monitor'] = $gateway['gateway'];
420

    
421
			$gateway['friendlyiface'] = $gateway['interface'];
422

    
423
			/* special treatment for tunnel interfaces */
424
			if ($gateway['ipprotocol'] == "inet6") {
425
				$gateway['interface'] = get_real_interface($gateway['interface'], "inet6");
426
				$interfaces_v6[$gateway['friendlyiface']] = $gateway['friendlyiface'];
427
			} else {
428
				$gateway['interface'] = get_real_interface($gateway['interface']);
429
				$interfaces_v4[$gateway['friendlyiface']] = $gateway['friendlyiface'];
430
			}
431

    
432
			/* entry has a default flag, use it */
433
			if (isset($gateway['defaultgw'])) {
434
				if ($gateway['ipprotocol'] == "inet") {
435
					$gateway['defaultgw'] = true;
436
					$found_defaultv4 = 1;
437
				} else if ($gateway['ipprotocol'] == "inet6") {
438
					$gateway['defaultgw'] = true;
439
					$found_defaultv6 = 1;
440
				}
441
			}
442
			/* include the gateway index as the attribute */
443
			$gateway['attribute'] = $i;
444

    
445
			$gateways_arr[$gateway['name']] = $gateway;
446
			$i++;
447
		}
448
	}
449
	unset($gateway);
450

    
451
	/* Loop through all interfaces with a gateway and add it to a array */
452
	if ($disabled == false)
453
		$iflist = get_configured_interface_with_descr();
454
	else
455
		$iflist = get_configured_interface_with_descr(false, true);
456

    
457
	/* Process/add dynamic v4 gateways. */
458
	foreach($iflist as $ifname => $friendly ) {
459
		if(! interface_has_gateway($ifname))
460
			continue;
461

    
462
		if (empty($config['interfaces'][$ifname]))
463
			continue;
464

    
465
		$ifcfg = &$config['interfaces'][$ifname];
466
		if(!isset($ifcfg['enable']))
467
			continue;
468

    
469
		if(!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr']))
470
			continue;
471

    
472
		if (isset($interfaces_v4[$ifname]))
473
			continue;
474

    
475
		$ctype = "";
476
		switch($ifcfg['ipaddr']) {
477
			case "dhcp":
478
			case "pppoe":
479
			case "pptp":
480
			case "ppp":
481
				$ctype = strtoupper($ifcfg['ipaddr']);
482
				break;
483
			default:
484
				if (substr($ifcfg['if'], 0, 4) ==  "ovpn")
485
					$ctype = "VPNv4";
486
				break;
487
		}
488
		$ctype = "_". strtoupper($ctype);
489

    
490
		$gateway = array();
491
		$gateway['dynamic'] = false;
492
		$gateway['ipprotocol'] = "inet";
493
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
494
		$gateway['interface'] = get_real_interface($ifname);
495
		$gateway['friendlyiface'] = $ifname;
496
		$gateway['name'] = "{$friendly}{$ctype}";
497
		$gateway['attribute'] = "system";
498

    
499
		if (($gateway['dynamic'] === "default") && ($found_defaultv4 == 0)) {
500
			$gateway['defaultgw'] = true;
501
			$gateway['dynamic'] = true;
502
			$found_defaultv4 = 1;
503
		}
504
		/* Loopback dummy for dynamic interfaces without a IP */
505
		if (!is_ipaddrv4($gateway['gateway']) && $gateway['dynamic'] == true)
506
			$gateway['gateway'] = "dynamic";
507

    
508
		/* automatically skip known static and dynamic gateways we have a array entry for */
509
		foreach($gateways_arr as $gateway_item) {
510
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name'])&& ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
511
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
512
					continue 2;
513
		}
514

    
515
		if (is_ipaddrv4($gateway['gateway']))
516
			$gateway['monitor'] = $gateway['gateway'];
517

    
518
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
519
		$gateways_arr[$gateway['name']] = $gateway;
520
	}
521
	unset($gateway);
522

    
523
	/* Process/add dynamic v6 gateways. */
524
	foreach($iflist as $ifname => $friendly ) {
525
		/* If the user has disabled IPv6, they probably don't want any IPv6 gateways. */
526
		if (!isset($config['system']['ipv6allow']))
527
			break;
528

    
529
		if(! interface_has_gatewayv6($ifname))
530
			continue;
531

    
532
		if (empty($config['interfaces'][$ifname]))
533
			continue;
534

    
535
		$ifcfg = &$config['interfaces'][$ifname];
536
		if(!isset($ifcfg['enable']))
537
			continue;
538

    
539
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
540
			continue;
541

    
542
		if(isset($interfaces_v6[$ifname]))
543
			continue;
544

    
545
		$ctype = "";
546
		switch($ifcfg['ipaddrv6']) {
547
			case "slaac":
548
			case "dhcp6":
549
			case "6to4":
550
			case "6rd":
551
				$ctype = strtoupper($ifcfg['ipaddrv6']);
552
				break;
553
			default:
554
				if (substr($ifcfg['if'], 0, 4) ==  "ovpn")
555
					$ctype = "VPNv6";
556
				break;
557
		}
558
		$ctype = "_". strtoupper($ctype);
559

    
560
		$gateway = array();
561
		$gateway['dynamic'] = false;
562
		$gateway['ipprotocol'] = "inet6";
563
		$gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
564
		$gateway['interface'] = get_real_interface($ifname, "inet6");
565
		switch($ifcfg['ipaddrv6']) {
566
			case "6rd":
567
			case "6to4":
568
				$gateway['dynamic'] = "default";
569
				break;
570
		}
571
		$gateway['friendlyiface'] = $ifname;
572
		$gateway['name'] = "{$friendly}{$ctype}";
573
		$gateway['attribute'] = "system";
574

    
575
		if (($gateway['dynamic'] === "default")  && ($found_defaultv6 == 0)) {
576
			$gateway['defaultgw'] = true;
577
			$gateway['dynamic'] = true;
578
			$found_defaultv6 = 1;
579
		}
580

    
581
		/* Loopback dummy for dynamic interfaces without a IP */
582
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
583
			$gateway['gateway'] = "dynamic6";
584

    
585
		/* automatically skip known static and dynamic gateways we have a array entry for */
586
		foreach($gateways_arr as $gateway_item) {
587
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
588
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
589
					continue 2;
590
		}
591

    
592
		if (is_ipaddrv6($gateway['gateway']))
593
			$gateway['monitor'] = $gateway['gateway'];
594

    
595
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
596
		$gateways_arr[$gateway['name']] = $gateway;
597
	}
598
	unset($gateway);
599

    
600
	/* FIXME: Should this be enabled.
601
	 * Some interface like wan might be default but have no info recorded
602
	 * the config. */
603
	/* this is a fallback if all else fails and we want to get packets out @smos */
604
	if ($found_defaultv4 == 0 || $found_defaultv6 == 0) {
605
		foreach ($gateways_arr as &$gateway) {
606
			if (($gateway['friendlyiface'] == "wan") && ($found_defaultv4 == 0) && (!isset($gateway['ipprotocol']) || ($gateway['ipprotocol'] == "inet"))) {
607
				if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgw")) {
608
					$gateway['defaultgw'] = true;
609
					$found_defaultv4 = 1;
610
				}
611
			}
612
			if (($gateway['friendlyiface'] == "wan") && ($found_defaultv6 == 0) && ($gateway['ipprotocol'] == "inet6")) {
613
				if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgwv6")) {
614
					$gateway['defaultgw'] = true;
615
					$found_defaultv6 = 1;
616
				}
617
			}
618
		}
619
	}
620

    
621
	if($localhost === true) {
622
		/* attach localhost for Null routes */
623
		$gwlo4 = array();
624
		$gwlo4['name'] = "Null4";
625
		$gwlo4['interface'] = "lo0";
626
		$gwlo4['ipprotocol'] = "inet";
627
		$gwlo4['gateway'] = "127.0.0.1";
628
		$gwlo6 = array();
629
		$gwlo6['name'] = "Null6";
630
		$gwlo6['interface'] = "lo0";
631
		$gwlo6['ipprotocol'] = "inet6";
632
		$gwlo6['gateway'] = "::1";
633
		$gateways_arr['Null4'] = $gwlo4;
634
		$gateways_arr['Null6'] = $gwlo6;
635
	}
636
	return($gateways_arr);
637
}
638

    
639
function fixup_default_gateway($ipprotocol, $gateways_status, $gateways_arr) {
640
	global $config, $g;
641
	/*
642
	 * NOTE: The code below is meant to replace the default gateway when it goes down.
643
	 *	This facilitates services running on pfSense itself and are not handled by a PBR to continue working.
644
	 */
645
	$upgw = "";
646
	$dfltgwdown = false;
647
	$dfltgwfound = false;
648
	foreach ($gateways_arr as $gwname => $gwsttng) {
649
		if (($gwsttng['ipprotocol'] == $ipprotocol) && isset($gwsttng['defaultgw'])) {
650
			$dfltgwfound = true;
651
			$dfltgwname = $gwname;
652
			if (!isset($gwsttng['monitor_disable']) && stristr($gateways_status[$gwname]['status'], "down"))
653
				$dfltgwdown = true;
654
		}
655
		/* Keep a record of the last up gateway */
656
		/* XXX: Blacklist lan for now since it might cause issues to those who have a gateway set for it */
657
		if (empty($upgw) && ($gwsttng['ipprotocol'] == $ipprotocol) && (isset($gwsttng['monitor_disable']) || !stristr($gateways_status[$gwname]['status'], "down")) && $gwsttng[$gwname]['friendlyiface'] != "lan")
658
			$upgw = $gwname;
659
		if ($dfltgwdown == true && !empty($upgw))
660
			break;
661
	}
662
	if ($dfltgwfound == false) {
663
		$gwname = convert_friendly_interface_to_friendly_descr("wan");
664
		if (!empty($gateways_status[$gwname]) && stristr($gateways_status[$gwname]['status'], "down"))
665
			$dfltgwdown = true;
666
	}
667
	if ($dfltgwdown == true && !empty($upgw)) {
668
		if (preg_match("/dynamic/i", $gateways_arr[$upgw]['gateway']))
669
			$gateways_arr[$upgw]['gateway'] = get_interface_gateway($gateways_arr[$upgw]['friendlyiface']);
670
		if (is_ipaddr($gateways_arr[$upgw]['gateway'])) {
671
			log_error("Default gateway down setting {$upgw} as default!");
672
			if(is_ipaddrv6($gateways_arr[$upgw]['gateway'])) {
673
				$inetfamily = "-inet6";
674
			} else {
675
				$inetfamily = "-inet";
676
			}
677
			mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$upgw]['gateway']}");
678
		}
679
	} else {
680
		$defaultgw = trim(`/sbin/route -n get -{$ipprotocol} default | /usr/bin/grep gateway | /usr/bin/sed 's/gateway://g'`, " \n");
681
		if(is_ipaddrv6($gateways_arr[$dfltgwname]['gateway'])) {
682
			$inetfamily = "-inet6";
683
		} else {
684
			$inetfamily = "-inet";
685
		}
686
		if ($defaultgw != $gateways_arr[$dfltgwname]['gateway'])
687
			mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$dfltgwname]['gateway']}");
688
	}
689
}
690

    
691
/*
692
 * Return an array with all gateway groups with name as key
693
 * All gateway groups will be processed before returning the array.
694
 */
695
function return_gateway_groups_array() {
696
	global $config, $g;
697

    
698
	/* fetch the current gateways status */
699
	$gateways_status = return_gateways_status(true);
700
	$gateways_arr = return_gateways_array();
701
	$gateway_groups_array = array();
702

    
703
	if (isset($config['system']['gw_switch_default'])) {
704
		fixup_default_gateway("inet", $gateways_status, $gateways_arr);
705
		fixup_default_gateway("inet6", $gateways_status, $gateways_arr);
706
	}
707
	if (is_array($config['gateways']['gateway_group'])) {
708
		$carplist = get_configured_carp_interface_list();
709
		foreach ($config['gateways']['gateway_group'] as $group) {
710
			/* create array with group gateways members separated by tier */
711
			$tiers = array();
712
			$backupplan = array();
713
			$gwvip_arr = array();
714
			foreach ($group['item'] as $item) {
715
				list($gwname, $tier, $vipname) = explode("|", $item);
716

    
717
				if (is_ipaddr($carplist[$vipname])) {
718
					if (!is_array($gwvip_arr[$group['name']]))
719
						$gwvip_arr[$group['name']] = array();
720
					$gwvip_arr[$group['name']][$gwname] = $vipname;
721
				}
722

    
723
				/* Do it here rather than reiterating again the group in case no member is up. */
724
				if (!is_array($backupplan[$tier]))
725
					$backupplan[$tier] = array();
726
				$backupplan[$tier][] = $gwname;
727

    
728
				/* check if the gateway is available before adding it to the array */
729
				if (is_array($gateways_status[$gwname])) {
730
					$status = $gateways_status[$gwname];
731
					$gwdown = false;
732
					if (stristr($status['status'], "down")) {
733
						$msg = sprintf(gettext("MONITOR: %s is down, removing from routing group {$group['name']}"), $gwname);
734
						$gwdown = true;
735
					} else if (stristr($status['status'], "loss") && strstr($group['trigger'], "loss")) {
736
						/* packet loss */
737
						$msg = sprintf(gettext("MONITOR: %s has packet loss, removing from routing group {$group['name']}"), $gwname);
738
						$gwdown = true;
739
					} else if (stristr($status['status'], "delay") && strstr($group['trigger'] , "latency")) {
740
						/* high latency */
741
						$msg = sprintf(gettext("MONITOR: %s has high latency, removing from routing group {$group['name']}"), $gwname);
742
						$gwdown = true;
743
					}
744
					if ($gwdown == true) {
745
						log_error($msg);
746
						notify_via_growl($msg);
747
						notify_via_smtp($msg);
748
					} else {
749
						/* Online add member */
750
						if (!is_array($tiers[$tier]))
751
							$tiers[$tier] = array();
752
						$tiers[$tier][] = $gwname;
753
					}
754
				} else if (isset($gateways_arr[$gwname]['monitor_disable']))
755
					$tiers[$tier][] = $gwname;
756
			}
757
			$tiers_count = count($tiers);
758
			if ($tiers_count == 0) {
759
				/* Oh dear, we have no members! Engage Plan B */
760
				if (!$g['booting']) {
761
					$msg = gettext("Gateways status could not be determined, considering all as up/active. (Group: {$group['name']})");
762
					log_error($msg);
763
					notify_via_growl($msg);
764
					//notify_via_smtp($msg);
765
				}
766
				$tiers = $backupplan;
767
			}
768
			/* sort the tiers array by the tier key */
769
			ksort($tiers);
770

    
771
			/* we do not really foreach the tiers as we stop after the first tier */
772
			foreach ($tiers as $tieridx => $tier) {
773
				/* process all gateways in this tier */
774
				foreach ($tier as $member) {
775
					/* determine interface gateway */
776
					if (isset($gateways_arr[$member])) {
777
						$gateway = $gateways_arr[$member];
778
						$int = $gateway['interface'];
779
						$gatewayip = "";
780
						if(is_ipaddr($gateway['gateway']))
781
							$gatewayip = $gateway['gateway'];
782
						else if (!empty($int))
783
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
784

    
785
						if (!empty($int) && is_ipaddr($gatewayip)) {
786
							$groupmember = array();
787
							$groupmember['int']  = $int;
788
							$groupmember['gwip']  = $gatewayip;
789
							$groupmember['weight']  = isset($gateway['weight']) ? $gateway['weight'] : 1;
790
							if (is_array($gwvip_arr[$group['name']])&& !empty($gwvip_arr[$group['name']][$member]))
791
								$groupmember['vip'] = $gwvip_arr[$group['name']][$member];
792
							$gateway_groups_array[$group['name']]['ipprotocol'] = $gateway['ipprotocol'];
793
							$gateway_groups_array[$group['name']][] = $groupmember;
794
						}
795
					}
796
				}
797
				/* we should have the 1st available tier now, exit stage left */
798
				if (count($gateway_groups_array[$group['name']]) > 0)
799
					break;
800
				else
801
					log_error("GATEWAYS: Group {$group['name']} did not have any gateways up on tier {$tieridx}!");
802
			}
803
		}
804
	}
805

    
806
	return ($gateway_groups_array);
807
}
808

    
809
/* Update DHCP WAN Interface ip address in gateway group item */
810
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
811
	global $config, $g;
812
	foreach($config['gateways']['gateway_item'] as & $gw) {
813
		if($gw['interface'] == $interface) {
814
			$current_gw = get_interface_gateway($interface);
815
			if($gw['gateway'] <> $current_gw) {
816
				$gw['gateway'] = $current_gw;
817
				$changed = true;
818
			}
819
		}
820
	}
821
	if($changed && $current_gw)
822
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interfac, $current_gw));
823
}
824

    
825
function lookup_gateway_ip_by_name($name) {
826

    
827
	$gateways_arr = return_gateways_array(false, true);
828
	foreach ($gateways_arr as $gname => $gw) {
829
		if ($gw['name'] === $name || $gname === $name)
830
			return $gw['gateway'];
831
	}
832

    
833
	return false;
834
}
835

    
836
function lookup_gateway_monitor_ip_by_name($name) {
837

    
838
	$gateways_arr = return_gateways_array(false, true);
839
	if (!empty($gateways_arr[$name])) {
840
		$gateway = $gateways_arr[$name];
841
		if(!is_ipaddr($gateway['monitor']))
842
			return $gateway['gateway'];
843

    
844
		return $gateway['monitor'];
845
	}
846

    
847
	return (false);
848
}
849

    
850
function lookup_gateway_interface_by_name($name) {
851

    
852
	$gateways_arr = return_gateways_array(false, true);
853
	if (!empty($gateways_arr[$name])) {
854
		$interfacegw = $gateways_arr[$name]['friendlyiface'];
855
		return ($interfacegw);
856
	}
857

    
858
	return (false);
859
}
860

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

    
864
	$gw = NULL;
865

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

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

    
886
	}
887

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

    
892
function get_interface_gateway_v6($interface, &$dynamic = false) {
893
	global $config, $g;
894

    
895
	$gw = NULL;
896
	$gwcfg = $config['interfaces'][$interface];
897
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
898
		foreach($config['gateways']['gateway_item'] as $gateway) {
899
			if(($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
900
				$gw = $gateway['gateway'];
901
				break;
902
			}
903
		}
904
	}
905

    
906
	// for dynamic interfaces we handle them through the $interface_router file.
907
	if (!is_ipaddrv6($gw) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
908
			$realif = get_real_interface($interface);
909
			if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
910
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
911
				$dynamic = true;
912
			}
913
			if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6"))
914
				$dynamic = "default";
915

    
916
	}
917
	/* return gateway */
918
	return ($gw);
919
}
920

    
921
/* Check a IP address against a gateway IP or name
922
 * to verify it's address family */
923
function validate_address_family($ipaddr, $gwname) {
924
	$v4ip = false;
925
	$v6ip = false;
926
	$v4gw = false;
927
	$v6gw = false;
928

    
929
	if(is_ipaddrv4($ipaddr))
930
		$v4ip = true;
931
	if(is_ipaddrv6($ipaddr))
932
		$v6ip = true;
933
	if(is_ipaddrv4($gwname))
934
		$v4gw = true;
935
	if(is_ipaddrv6($gwname))
936
		$v6gw = true;
937

    
938
	if($v4ip && $v4gw)
939
		return true;
940
	if($v6ip && $v6gw)
941
		return true;
942

    
943
	/* still no match, carry on, lookup gateways */
944
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
945
		$v4gw = true;
946
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
947
		$v6gw = true;
948

    
949
	$gw_array = return_gateways_array();
950
	if(is_array($gw_array[$gwname])) {
951
		switch($gw_array[$gwname]['ipprotocol']) {
952
			case "inet":
953
				$v4gw = true;
954
				break;
955
			case "inet6":
956
				$v6gw = true;
957
				break;
958
		}
959
	}
960

    
961
	if($v4ip && $v4gw)
962
		return true;
963
	if($v6ip && $v6gw)
964
		return true;
965

    
966
	return false;
967
}
968

    
969
/* check if a interface is part of a gateway group */
970
function interface_gateway_group_member($interface) {
971
	global $config;
972

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

    
978
	$gateways_arr = return_gateways_array(false, true);
979
	foreach($groups as $group) {
980
		if(is_array($group['item'])) {
981
			foreach($group['item'] as $item) {
982
				$elements = explode("|", $item);
983
				$gwname = $elements[0];
984
				if ($interface == $gateways_arr[$gwname]['interface']) {
985
					unset($gateways_arr);
986
					return true;
987
				}
988
			}
989
		}
990
	}
991
	unset($gateways_arr);
992

    
993
	return false;
994
}
995

    
996
function gateway_is_gwgroup_member($name) {
997
	global $config;
998

    
999
	if (is_array($config['gateways']['gateway_group']))
1000
		$groups = $config['gateways']['gateway_group'];
1001
	else
1002
		return false;
1003

    
1004
	$members = array();
1005
	foreach($groups as $group) {
1006
		if (is_array($group['item'])) {
1007
			foreach($group['item'] as $item) {
1008
				$elements = explode("|", $item);
1009
				$gwname = $elements[0];
1010
				if ($name == $elements[0])
1011
					$members[] = $group['name'];
1012
			}
1013
		}
1014
	}
1015

    
1016
	return $members;
1017
}
1018
?>
(24-24/66)