Project

General

Profile

Download (31.6 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
  Copyright (C) 2008 Bill Marquette, Seth Mos
4
  Copyright (C) 2010 Ermal Luçi
5
  All rights reserved.
6

    
7
  Redistribution and use in source and binary forms, with or without
8
  modification, are permitted provided that the following conditions are met:
9

    
10
  1. Redistributions of source code must retain the above copyright notice,
11
  this list of conditions and the following disclaimer.
12

    
13
  2. Redistributions in binary form must reproduce the above copyright
14
  notice, this list of conditions and the following disclaimer in the
15
  documentation and/or other materials provided with the distribution.
16

    
17
  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
18
  INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
19
  AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
20
  AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
21
  OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22
  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23
  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24
  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25
  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26
  POSSIBILITY OF SUCH DAMAGE.
27

    
28
	pfSense_BUILDER_BINARIES:	/usr/bin/killall	/sbin/route	/usr/local/sbin/apinger
29
	pfSense_MODULE:	routing
30

    
31
 */
32
require_once("config.inc");
33

    
34
/* Returns an array of default values used for apinger.conf */
35
function return_apinger_defaults() {
36
	return array(
37
		"latencylow" => "200",
38
		"latencyhigh" => "500",
39
		"losslow" => "10",
40
		"losshigh" => "20",
41
		"interval" => "1",
42
		"down" => "10");
43
	}
44

    
45
/*
46
 * Creates monitoring configuration file and
47
 * adds appropriate static routes.
48
 */
49
function setup_gateways_monitor() {
50
	global $config, $g;
51

    
52
	$gateways_arr = return_gateways_array();
53
	if (!is_array($gateways_arr)) {
54
		log_error("No gateways to monitor. Apinger will not be run.");
55
		killbypid("{$g['varrun_path']}/apinger.pid");
56
		@unlink("{$g['varrun_path']}/apinger.status");
57
		return;
58
	}
59

    
60
	$apinger_default = return_apinger_defaults();
61
	$fd = fopen("{$g['varetc_path']}/apinger.conf", "w");
62
	$apingerconfig = <<<EOD
63

    
64
# pfSense apinger configuration file. Automatically Generated!
65

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
143
EOD;
144

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

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

    
161
		/* Interface ip is needed since apinger will bind a socket to it. */
162
		if (is_ipaddrv4($gateway['gateway'])) {
163
			$gwifip = find_interface_ip($gateway['interface'], true);
164
			if (!is_ipaddrv4($gwifip))
165
				continue; //Skip this target
166
		} else if (is_ipaddrv6($gateway['gateway'])) {
167
			/* link locals really need a different src ip */
168
			if(preg_match("/fe80:/i", $gateway['gateway'])) {
169
				$linklocal = explode("%", find_interface_ipv6_ll($gateway['interface'], true));
170
				$gwifip = $linklocal[0];
171
				$ifscope = "%". $linklocal[1];
172
			} else {
173
				$gwifip = find_interface_ipv6($gateway['interface'], true);
174
			}
175
			if (!is_ipaddrv6($gwifip))
176
				continue; //Skip this target
177
		} else
178
			continue;
179

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

    
234
		$apingercfg .= "	rrd file \"{$g['vardb_path']}/rrd/{$gateway['name']}-quality.rrd\"\n";
235
		$apingercfg .= "}\n";
236
		$apingercfg .= "\n";
237
		/*
238
		 * If the gateway is the same as the monitor we do not add a
239
		 * route as this will break the routing table.
240
		 * Add static routes for each gateway with their monitor IP
241
		 * not strictly necessary but is a added level of protection.
242
		 */
243
		if (is_ipaddr($gateway['gateway']) && $gateway['monitor'] != $gateway['gateway']) {
244
			log_error(sprintf(gettext('Removing static route for monitor %1$s and adding a new route through %2$s'), $gateway['monitor'], $gateway['gateway']));
245
			if(is_ipaddrv6($gateway['gateway'])) {
246
				$inetfamily = "-inet6";
247
			} else {
248
				$inetfamily = "-inet";
249
			}
250
			// mwexec("/sbin/route change {$inetfamily} -host " . escapeshellarg($gateway['monitor']) .
251
			//	" " . escapeshellarg($gateway['gateway']), true);
252
		}
253

    
254
		$apingerconfig .= $alarmscfg;
255
		$apingerconfig .= $apingercfg;
256
	}
257
	fwrite($fd, $apingerconfig);
258
	fclose($fd);
259
	unset($apingerconfig);
260

    
261
	killbypid("{$g['varrun_path']}/apinger.pid");
262
	if (is_dir("{$g['tmp_path']}"))
263
		chmod("{$g['tmp_path']}", 01777);
264
	if (!is_dir("{$g['vardb_path']}/rrd"))
265
		mkdir("{$g['vardb_path']}/rrd", 0775);
266

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

    
269
	/* start a new apinger process */
270
	@unlink("{$g['varrun_path']}/apinger.status");
271
	sleep(1);
272
	mwexec_bg("/usr/local/sbin/apinger -c {$g['varetc_path']}/apinger.conf");
273

    
274
	return 0;
275
}
276

    
277
/* return the status of the apinger targets as a array */
278
function return_gateways_status($byname = false) {
279
	global $config, $g;
280

    
281
	$apingerstatus = array();
282
	if (file_exists("{$g['varrun_path']}/apinger.status")) {
283
		$apingerstatus = file("{$g['varrun_path']}/apinger.status");
284
	}
285

    
286
	$status = array();
287
	foreach($apingerstatus as $line) {
288
		$info = explode("|", $line);
289
		if ($byname == false)
290
			$target = $info[0];
291
		else
292
			$target = $info[2];
293

    
294
		$status[$target] = array();
295
		$status[$target]['monitorip'] = $info[0];
296
		$status[$target]['srcip'] = $info[1];
297
		$status[$target]['name'] = $info[2];
298
		$status[$target]['lastcheck'] = $info[5] ? date('r', $info[5]) : date('r');
299
		$status[$target]['delay'] = empty($info[6]) ? "0ms" : round($info[6], 1) ."ms" ;
300
		$status[$target]['loss'] = empty($info[7]) ? "0.0%" : round($info[7], 1) . "%";
301
		$status[$target]['status'] = trim($info[8]);
302
	}
303

    
304
	/* tack on any gateways that have monitoring disabled
305
	 * or are down, which could cause gateway groups to fail */
306
	$gateways_arr = return_gateways_array();
307
	foreach($gateways_arr as $gwitem) {
308
		if(!isset($gwitem['monitor_disable']))
309
			continue;
310
		if(!is_ipaddr($gwitem['monitorip'])) {
311
			$realif = $gwitem['interface'];
312
			$tgtip = get_interface_gateway($realif);
313
			if (!is_ipaddr($tgtip))
314
				$tgtip = "none";
315
			$srcip = find_interface_ip($realif);
316
		} else {
317
			$tgtip = $gwitem['monitorip'];
318
			$srcip = find_interface_ip($realif);
319
		}
320
		if($byname == true)
321
			$target = $gwitem['name'];
322
		else
323
			$target = $tgtip;
324

    
325
		/* failsafe for down interfaces */
326
		if($target == "none") {
327
			$target = $gwitem['name'];
328
			$status[$target]['name'] = $gwitem['name'];
329
			$status[$target]['lastcheck'] = date('r');
330
			$status[$target]['delay'] = "0.0ms";
331
			$status[$target]['loss'] = "100.0%";
332
			$status[$target]['status'] = "down";
333
		} else {
334
			$status[$target]['monitorip'] = $tgtip;
335
			$status[$target]['srcip'] = $srcip;
336
			$status[$target]['name'] = $gwitem['name'];
337
			$status[$target]['lastcheck'] = date('r');
338
			$status[$target]['delay'] = "0.0ms";
339
			$status[$target]['loss'] = "0.0%";
340
			$status[$target]['status'] = "none";
341
		}
342
	}
343
	return($status);
344
}
345

    
346
/* Return all configured gateways on the system */
347
function return_gateways_array($disabled = false, $localhost = false) {
348
	global $config, $g;
349

    
350
	$gateways_arr = array();
351

    
352
	$found_defaultv4 = 0;
353
	$found_defaultv6 = 0;
354

    
355
	$interfaces_v4 = array();
356
	$interfaces_v6 = array();
357

    
358
	$i = 0;
359
	/* Process/add all the configured gateways. */
360
	if (is_array($config['gateways']['gateway_item'])) {
361
		foreach ($config['gateways']['gateway_item'] as $gateway) {
362
			if (empty($config['interfaces'][$gateway['interface']]))
363
				continue;
364
			$wancfg = $config['interfaces'][$gateway['interface']];
365

    
366
			/* skip disabled interfaces */
367
			if (!isset($wancfg['enable']))
368
				continue;
369

    
370
			/* if the gateway is dynamic and we can find the IPv4, Great! */
371
			if (empty($gateway['gateway']) || $gateway['gateway'] == "dynamic" || $gateway['gateway'] == "dynamic6") {
372
				if ($gateway['ipprotocol'] == "inet") {
373
					/* we know which interfaces is dynamic, this should be made a function */
374
					$gateway['ipprotocol'] = "inet";
375
					$gateway['gateway'] = get_interface_gateway($gateway['interface']);
376
					/* no IP address found, set to dynamic */
377
					if (!is_ipaddrv4($gateway['gateway']))
378
						$gateway['gateway'] = "dynamic";
379
					$gateway['dynamic'] = true;
380
				}
381

    
382
				/* if the gateway is dynamic6 and we can find the IPv6, Great! */
383
				else if ($gateway['ipprotocol'] == "inet6") {
384
					/* we know which interfaces is dynamic, this should be made a function, and for v6 too */
385
					$gateway['ipprotocol'] = "inet6";
386
					$gateway['gateway'] = get_interface_gateway_v6($gateway['interface']);
387
					/* no IPv6 address found, set to dynamic6 */
388
					if (!is_ipaddrv6($gateway['gateway']))
389
						$gateway['gateway'] = "dynamic6";
390
					$gateway['dynamic'] = true;
391
				}
392
			} else {
393
				/* getting this detection right is hard at this point because we still don't
394
				 * store the address family in the gateway item */
395
				if (is_ipaddrv4($gateway['gateway']))
396
					$gateway['ipprotocol'] = "inet";
397
				else if(is_ipaddrv6($gateway['gateway']))
398
					$gateway['ipprotocol'] = "inet6";
399
			}
400

    
401
			if (isset($gateway['monitor_disable']))
402
				$gateway['monitor_disable'] = true;
403
			else if (empty($gateway['monitor']))
404
				$gateway['monitor'] = $gateway['gateway'];
405

    
406
			$gateway['friendlyiface'] = $gateway['interface'];
407

    
408
			/* special treatment for tunnel interfaces */
409
			if ($gateway['ipprotocol'] == "inet6") {
410
				$gateway['interface'] = get_real_interface($gateway['interface'], "inet6");
411
				$interfaces_v6[$gateway['friendlyiface']] = $gateway['friendlyiface'];
412
			} else {
413
				$gateway['interface'] = get_real_interface($gateway['interface']);
414
				$interfaces_v4[$gateway['friendlyiface']] = $gateway['friendlyiface'];
415
			}
416

    
417
			/* entry has a default flag, use it */
418
			if (isset($gateway['defaultgw'])) {
419
				if ($gateway['ipprotocol'] == "inet") {
420
					$gateway['defaultgw'] = true;
421
					$found_defaultv4 = 1;
422
				} else if ($gateway['ipprotocol'] == "inet6") {
423
					$gateway['defaultgw'] = true;
424
					$found_defaultv6 = 1;
425
				}
426
			}
427
			/* include the gateway index as the attribute */
428
			$gateway['attribute'] = $i;
429

    
430
			$gateways_arr[$gateway['name']] = $gateway;
431
			$i++;
432
		}
433
	}
434
	unset($gateway);
435

    
436
	/* Loop through all interfaces with a gateway and add it to a array */
437
	if ($disabled == false)
438
		$iflist = get_configured_interface_with_descr();
439
	else
440
		$iflist = get_configured_interface_with_descr(false, true);
441

    
442
	/* Process/add dynamic v4 gateways. */
443
	foreach($iflist as $ifname => $friendly ) {
444
		if(! interface_has_gateway($ifname))
445
			continue;
446

    
447
		if (empty($config['interfaces'][$ifname]))
448
			continue;
449

    
450
		$ifcfg = &$config['interfaces'][$ifname];
451
		if(!isset($ifcfg['enable']))
452
			continue;
453

    
454
		if(!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr']))
455
			continue;
456

    
457
		if (isset($interfaces_v4[$ifname]))
458
			continue;
459

    
460
		$ctype = "";
461
		switch($ifcfg['ipaddr']) {
462
			case "dhcp":
463
			case "pppoe":
464
			case "pptp":
465
			case "ppp":
466
				$ctype = strtoupper($ifcfg['ipaddr']);
467
				break;
468
			default:
469
				if (substr($ifcfg['if'], 0, 4) ==  "ovpn")
470
					$ctype = "VPNv4";
471
				break;
472
		}
473
		$ctype = "_". strtoupper($ctype);
474

    
475
		$gateway = array();
476
		$gateway['dynamic'] = false;
477
		$gateway['ipprotocol'] = "inet";
478
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
479
		$gateway['interface'] = get_real_interface($ifname);
480
		$gateway['friendlyiface'] = $ifname;
481
		$gateway['name'] = "{$friendly}{$ctype}";
482
		$gateway['attribute'] = "system";
483

    
484
		if (($gateway['dynamic'] === "default") && ($found_defaultv4 == 0)) {
485
			$gateway['defaultgw'] = true;
486
			$gateway['dynamic'] = true;
487
			$found_defaultv4 = 1;
488
		}
489
		/* Loopback dummy for dynamic interfaces without a IP */
490
		if (!is_ipaddrv4($gateway['gateway']) && $gateway['dynamic'] == true)
491
			$gateway['gateway'] = "dynamic";
492

    
493
		/* automatically skip known static and dynamic gateways we have a array entry for */
494
		foreach($gateways_arr as $gateway_item) {
495
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name'])&& ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
496
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
497
					continue 2;
498
		}
499

    
500
		if (is_ipaddrv4($gateway['gateway']))
501
			$gateway['monitor'] = $gateway['gateway'];
502

    
503
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
504
		$gateways_arr[$gateway['name']] = $gateway;
505
	}
506
	unset($gateway);
507

    
508
	/* Process/add dynamic v6 gateways. */
509
	foreach($iflist as $ifname => $friendly ) {
510
		/* If the user has disabled IPv6, they probably don't want any IPv6 gateways. */
511
		if (!isset($config['system']['ipv6allow']))
512
			break;
513

    
514
		if(! interface_has_gatewayv6($ifname))
515
			continue;
516

    
517
		if (empty($config['interfaces'][$ifname]))
518
			continue;
519

    
520
		$ifcfg = &$config['interfaces'][$ifname];
521
		if(!isset($ifcfg['enable']))
522
			continue;
523

    
524
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
525
			continue;
526

    
527
		if(isset($interfaces_v6[$ifname]))
528
			continue;
529

    
530
		$ctype = "";
531
		switch($ifcfg['ipaddrv6']) {
532
			case "slaac":
533
			case "dhcp6":
534
			case "6to4":
535
			case "6rd":
536
				$ctype = strtoupper($ifcfg['ipaddrv6']);
537
				break;
538
			default:
539
				if (substr($ifcfg['if'], 0, 4) ==  "ovpn")
540
					$ctype = "VPNv6";
541
				break;
542
		}
543
		$ctype = "_". strtoupper($ctype);
544

    
545
		$gateway = array();
546
		$gateway['dynamic'] = false;
547
		$gateway['ipprotocol'] = "inet6";
548
		$gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
549
		$gateway['interface'] = get_real_interface($ifname, "inet6");
550
		switch($ifcfg['ipaddrv6']) {
551
			case "6rd":
552
			case "6to4":
553
				$gateway['dynamic'] = "default";
554
				break;
555
		}
556
		$gateway['friendlyiface'] = $ifname;
557
		$gateway['name'] = "{$friendly}{$ctype}";
558
		$gateway['attribute'] = "system";
559

    
560
		if (($gateway['dynamic'] === "default")  && ($found_defaultv6 == 0)) {
561
			$gateway['defaultgw'] = true;
562
			$gateway['dynamic'] = true;
563
			$found_defaultv6 = 1;
564
		}
565

    
566
		/* Loopback dummy for dynamic interfaces without a IP */
567
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
568
			$gateway['gateway'] = "dynamic6";
569

    
570
		/* automatically skip known static and dynamic gateways we have a array entry for */
571
		foreach($gateways_arr as $gateway_item) {
572
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
573
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
574
					continue 2;
575
		}
576

    
577
		if (is_ipaddrv6($gateway['gateway']))
578
			$gateway['monitor'] = $gateway['gateway'];
579

    
580
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
581
		$gateways_arr[$gateway['name']] = $gateway;
582
	}
583
	unset($gateway);
584

    
585
	/* FIXME: Should this be enabled.
586
	 * Some interface like wan might be default but have no info recorded
587
	 * the config. */
588
	/* this is a fallback if all else fails and we want to get packets out @smos */
589
	if ($found_defaultv4 == 0 || $found_defaultv6 == 0) {
590
		foreach ($gateways_arr as &$gateway) {
591
			if (($gateway['friendlyiface'] == "wan") && ($found_defaultv4 == 0) && (!isset($gateway['ipprotocol']) || ($gateway['ipprotocol'] == "inet"))) {
592
				if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgw")) {
593
					$gateway['defaultgw'] = true;
594
					$found_defaultv4 = 1;
595
				}
596
			}
597
			if (($gateway['friendlyiface'] == "wan") && ($found_defaultv6 == 0) && ($gateway['ipprotocol'] == "inet6")) {
598
				if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgwv6")) {
599
					$gateway['defaultgw'] = true;
600
					$found_defaultv6 = 1;
601
				}
602
			}
603
		}
604
	}
605

    
606
	if($localhost === true) {
607
		/* attach localhost for Null routes */
608
		$gwlo4 = array();
609
		$gwlo4['name'] = "Null4";
610
		$gwlo4['interface'] = "lo0";
611
		$gwlo4['ipprotocol'] = "inet";
612
		$gwlo4['gateway'] = "127.0.0.1";
613
		$gwlo6 = array();
614
		$gwlo6['name'] = "Null6";
615
		$gwlo6['interface'] = "lo0";
616
		$gwlo6['ipprotocol'] = "inet6";
617
		$gwlo6['gateway'] = "::1";
618
		$gateways_arr['Null4'] = $gwlo4;
619
		$gateways_arr['Null6'] = $gwlo6;
620
	}
621
	return($gateways_arr);
622
}
623

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

    
676
/*
677
 * Return an array with all gateway groups with name as key
678
 * All gateway groups will be processed before returning the array.
679
 */
680
function return_gateway_groups_array() {
681
	global $config, $g;
682

    
683
	/* fetch the current gateways status */
684
	$gateways_status = return_gateways_status(true);
685
	$gateways_arr = return_gateways_array();
686
	$gateway_groups_array = array();
687

    
688
	if (isset($config['system']['gw_switch_default'])) {
689
		fixup_default_gateway("inet", $gateways_status, $gateways_arr);
690
		fixup_default_gateway("inet6", $gateways_status, $gateways_arr);
691
	}
692
	if (is_array($config['gateways']['gateway_group'])) {
693
		$carplist = get_configured_carp_interface_list();
694
		foreach ($config['gateways']['gateway_group'] as $group) {
695
			/* create array with group gateways members seperated by tier */
696
			$tiers = array();
697
			$backupplan = array();
698
			$gwvip_arr = array();
699
			foreach ($group['item'] as $item) {
700
				list($gwname, $tier, $vipname) = explode("|", $item);
701

    
702
				if (is_ipaddr($carplist[$vipname])) {
703
					if (!is_array($group['name']))
704
						$gwvip_arr[$group['name']] = array();
705
					$gwvip_arr[$group['name']][$gwname] = $vipname;
706
				}
707

    
708
				/* Do it here rather than reiterating again the group in case no member is up. */
709
				if (!is_array($backupplan[$tier]))
710
					$backupplan[$tier] = array();
711
				$backupplan[$tier][] = $gwname;
712

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

    
756
			/* we do not really foreach the tiers as we stop after the first tier */
757
			foreach ($tiers as $tieridx => $tier) {
758
				/* process all gateways in this tier */
759
				foreach ($tier as $member) {
760
					/* determine interface gateway */
761
					if (isset($gateways_arr[$member])) {
762
						$gateway = $gateways_arr[$member];
763
						$int = $gateway['interface'];
764
						$gatewayip = "";
765
						if(is_ipaddr($gateway['gateway']))
766
							$gatewayip = $gateway['gateway'];
767
						else if (!empty($int))
768
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
769

    
770
						if (!empty($int) && is_ipaddr($gatewayip)) {
771
							$groupmember = array();
772
							$groupmember['int']  = $int;
773
							$groupmember['gwip']  = $gatewayip;
774
							$groupmember['weight']  = isset($gateway['weight']) ? $gateway['weight'] : 1;
775
							if (is_array($gwvip_arr[$group['name']])&& !empty($gwvip_arr[$group['name']][$gwname]))
776
								$groupmember['vip'] = $gwvip_arr[$group['name']][$gwname];
777
							$gateway_groups_array[$group['name']]['ipprotocol'] = $gateway['ipprotocol'];
778
							$gateway_groups_array[$group['name']][] = $groupmember;
779
						}
780
					}
781
				}
782
				/* we should have the 1st available tier now, exit stage left */
783
				if (count($gateway_groups_array[$group['name']]) > 0)
784
					break;
785
				else
786
					log_error("GATEWAYS: Group {$group['name']} did not have any gateways up on tier {$tieridx}!");
787
			}
788
		}
789
	}
790

    
791
	return ($gateway_groups_array);
792
}
793

    
794
/* Update DHCP WAN Interface ip address in gateway group item */
795
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
796
	global $config, $g;
797
	foreach($config['gateways']['gateway_item'] as & $gw) {
798
		if($gw['interface'] == $interface) {
799
			$current_gw = get_interface_gateway($interface);
800
			if($gw['gateway'] <> $current_gw) {
801
				$gw['gateway'] = $current_gw;
802
				$changed = true;
803
			}
804
		}
805
	}
806
	if($changed && $current_gw)
807
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interfac, $current_gw));
808
}
809

    
810
function lookup_gateway_ip_by_name($name) {
811

    
812
	$gateways_arr = return_gateways_array(false, true);
813
	foreach ($gateways_arr as $gname => $gw) {
814
		if ($gw['name'] === $name || $gname === $name)
815
			return $gw['gateway'];
816
	}
817

    
818
	return false;
819
}
820

    
821
function lookup_gateway_monitor_ip_by_name($name) {
822

    
823
	$gateways_arr = return_gateways_array(false, true);
824
	if (!empty($gateways_arr[$name])) {
825
		$gateway = $gateways_arr[$name];
826
		if(!is_ipaddr($gateway['monitor']))
827
			return $gateway['gateway'];
828

    
829
		return $gateway['monitor'];
830
	}
831

    
832
	return (false);
833
}
834

    
835
function lookup_gateway_interface_by_name($name) {
836

    
837
	$gateways_arr = return_gateways_array(false, true);
838
	if (!empty($gateways_arr[$name])) {
839
		$interfacegw = $gateways_arr[$name]['friendlyiface'];
840
		return ($interfacegw);
841
	}
842

    
843
	return (false);
844
}
845

    
846
function get_interface_gateway($interface, &$dynamic = false) {
847
	global $config, $g;
848

    
849
	$gw = NULL;
850

    
851
	$gwcfg = $config['interfaces'][$interface];
852
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
853
		foreach($config['gateways']['gateway_item'] as $gateway) {
854
			if(($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
855
				$gw = $gateway['gateway'];
856
				break;
857
			}
858
		}
859
	}
860

    
861
	// for dynamic interfaces we handle them through the $interface_router file.
862
	if (!is_ipaddrv4($gw) && !is_ipaddrv4($gwcfg['ipaddr'])) {
863
		$realif = get_real_interface($interface);
864
		if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
865
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
866
			$dynamic = true;
867
		}
868
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw"))
869
			$dynamic = "default";
870

    
871
	}
872

    
873
	/* return gateway */
874
	return ($gw);
875
}
876

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

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

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

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

    
906
/* Check a IP address against a gateway IP or name
907
 * to verify it's address family */
908
function validate_address_family($ipaddr, $gwname) {
909
	$v4ip = false;
910
	$v6ip = false;
911
	$v4gw = false;
912
	$v6gw = false;
913

    
914
	if(is_ipaddrv4($ipaddr))
915
		$v4ip = true;
916
	if(is_ipaddrv6($ipaddr))
917
		$v6ip = true;
918
	if(is_ipaddrv4($gwname))
919
		$v4gw = true;
920
	if(is_ipaddrv6($gwname))
921
		$v6gw = true;
922

    
923
	if($v4ip && $v4gw)
924
		return true;
925
	if($v6ip && $v6gw)
926
		return true;
927

    
928
	/* still no match, carry on, lookup gateways */
929
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
930
		$v4gw = true;
931
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
932
		$v6gw = true;
933

    
934
	$gw_array = return_gateways_array();
935
	if(is_array($gw_array[$gwname])) {
936
		switch($gw_array[$gwname]['ipprotocol']) {
937
			case "inet":
938
				$v4gw = true;
939
				break;
940
			case "inet6":
941
				$v6gw = true;
942
				break;
943
		}
944
	}
945

    
946
	if($v4ip && $v4gw)
947
		return true;
948
	if($v6ip && $v6gw)
949
		return true;
950

    
951
	return false;
952
}
953

    
954
/* check if a interface is part of a gateway group */
955
function interface_gateway_group_member($interface) {
956
	global $config;
957

    
958
	if (is_array($config['gateways']['gateway_group']))
959
		$groups = $config['gateways']['gateway_group'];
960
	else
961
		return false;
962

    
963
	$gateways_arr = return_gateways_array(false, true);
964
	foreach($groups as $group) {
965
		if(is_array($group['item'])) {
966
			foreach($group['item'] as $item) {
967
				$elements = explode("|", $item);
968
				$gwname = $elements[0];
969
				if ($interface == $gateways_arr[$gwname]['interface']) {
970
					unset($gateways_arr);
971
					return true;
972
				}
973
			}
974
		}
975
	}
976
	unset($gateways_arr);
977

    
978
	return false;
979
}
980

    
981
function gateway_is_gwgroup_member($name) {
982
	global $config;
983

    
984
	if (is_array($config['gateways']['gateway_group']))
985
		$groups = $config['gateways']['gateway_group'];
986
	else
987
		return false;
988

    
989
	$members = array();
990
	foreach($groups as $group) {
991
		if (is_array($group['item'])) {
992
			foreach($group['item'] as $item) {
993
				$elements = explode("|", $item);
994
				$gwname = $elements[0];
995
				if ($name == $elements[0])
996
					$members[] = $group['name'];
997
			}
998
		}
999
	}
1000

    
1001
	return $members;
1002
}
1003
?>
(24-24/66)