Project

General

Profile

Download (31.2 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
				$gwifip = find_interface_ipv6_ll($gateway['interface'], true);
169
			} else {
170
				$gwifip = find_interface_ipv6($gateway['interface'], true);
171
			}
172
			if (is_linklocal($gateway['monitor']) && !strstr($gateway['monitor'], '%'))
173
				$gateway['monitor'] .= "%{$gateway['interface']}";
174
			if (!is_ipaddrv6($gwifip))
175
				continue; //Skip this target
176
		} else
177
			continue;
178

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

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

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

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

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

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

    
261
	return 0;
262
}
263

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

    
268
	$apingerstatus = array();
269
	/* Always get the latest status from apinger */
270
	if (file_exists("{$g['varrun_path']}/apinger.pid"))
271
                sigkillbypid("{$g['varrun_path']}/apinger.pid", "USR1");
272
	if (file_exists("{$g['varrun_path']}/apinger.status")) {
273
		$apingerstatus = file("{$g['varrun_path']}/apinger.status");
274
	} else
275
		$apingerstatus = array();
276

    
277
	$status = array();
278
	foreach($apingerstatus as $line) {
279
		$info = explode("|", $line);
280
		if ($byname == false)
281
			$target = $info[0];
282
		else
283
			$target = $info[2];
284

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

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

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

    
337
/* Return all configured gateways on the system */
338
function return_gateways_array($disabled = false, $localhost = false) {
339
	global $config, $g;
340

    
341
	$gateways_arr = array();
342

    
343
	$found_defaultv4 = 0;
344
	$found_defaultv6 = 0;
345

    
346
	$interfaces_v4 = array();
347
	$interfaces_v6 = array();
348

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

    
357
			/* skip disabled interfaces */
358
			if (!isset($wancfg['enable']))
359
				continue;
360

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

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

    
392
			if (isset($gateway['monitor_disable']))
393
				$gateway['monitor_disable'] = true;
394
			else if (empty($gateway['monitor']))
395
				$gateway['monitor'] = $gateway['gateway'];
396

    
397
			$gateway['friendlyiface'] = $gateway['interface'];
398

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

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

    
421
			$gateways_arr[$gateway['name']] = $gateway;
422
			$i++;
423
		}
424
	}
425
	unset($gateway);
426

    
427
	/* Loop through all interfaces with a gateway and add it to a array */
428
	if ($disabled == false)
429
		$iflist = get_configured_interface_with_descr();
430
	else
431
		$iflist = get_configured_interface_with_descr(false, true);
432

    
433
	/* Process/add dynamic v4 gateways. */
434
	foreach($iflist as $ifname => $friendly ) {
435
		if(! interface_has_gateway($ifname))
436
			continue;
437

    
438
		if (empty($config['interfaces'][$ifname]))
439
			continue;
440

    
441
		$ifcfg = &$config['interfaces'][$ifname];
442
		if(!isset($ifcfg['enable']))
443
			continue;
444

    
445
		if(!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr']))
446
			continue;
447

    
448
		if (isset($interfaces_v4[$ifname]))
449
			continue;
450

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

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

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

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

    
491
		if (is_ipaddrv4($gateway['gateway']))
492
			$gateway['monitor'] = $gateway['gateway'];
493

    
494
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
495
		$gateways_arr[$gateway['name']] = $gateway;
496
	}
497
	unset($gateway);
498

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

    
505
		if(! interface_has_gatewayv6($ifname))
506
			continue;
507

    
508
		if (empty($config['interfaces'][$ifname]))
509
			continue;
510

    
511
		$ifcfg = &$config['interfaces'][$ifname];
512
		if(!isset($ifcfg['enable']))
513
			continue;
514

    
515
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
516
			continue;
517

    
518
		if(isset($interfaces_v6[$ifname]))
519
			continue;
520

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

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

    
551
		if (($gateway['dynamic'] === "default")  && ($found_defaultv6 == 0)) {
552
			$gateway['defaultgw'] = true;
553
			$gateway['dynamic'] = true;
554
			$found_defaultv6 = 1;
555
		}
556

    
557
		/* Loopback dummy for dynamic interfaces without a IP */
558
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
559
			$gateway['gateway'] = "dynamic6";
560

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

    
568
		if (is_ipaddrv6($gateway['gateway']))
569
			$gateway['monitor'] = $gateway['gateway'];
570

    
571
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
572
		$gateways_arr[$gateway['name']] = $gateway;
573
	}
574
	unset($gateway);
575

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

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

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

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

    
674
	/* fetch the current gateways status */
675
	$gateways_status = return_gateways_status(true);
676
	$gateways_arr = return_gateways_array();
677
	$gateway_groups_array = array();
678

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

    
693
				if (is_ipaddr($carplist[$vipname])) {
694
					if (!is_array($gwvip_arr[$group['name']]))
695
						$gwvip_arr[$group['name']] = array();
696
					$gwvip_arr[$group['name']][$gwname] = $vipname;
697
				}
698

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

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

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

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

    
782
	return ($gateway_groups_array);
783
}
784

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

    
801
function lookup_gateway_ip_by_name($name) {
802

    
803
	$gateways_arr = return_gateways_array(false, true);
804
	foreach ($gateways_arr as $gname => $gw) {
805
		if ($gw['name'] === $name || $gname === $name)
806
			return $gw['gateway'];
807
	}
808

    
809
	return false;
810
}
811

    
812
function lookup_gateway_monitor_ip_by_name($name) {
813

    
814
	$gateways_arr = return_gateways_array(false, true);
815
	if (!empty($gateways_arr[$name])) {
816
		$gateway = $gateways_arr[$name];
817
		if(!is_ipaddr($gateway['monitor']))
818
			return $gateway['gateway'];
819

    
820
		return $gateway['monitor'];
821
	}
822

    
823
	return (false);
824
}
825

    
826
function lookup_gateway_interface_by_name($name) {
827

    
828
	$gateways_arr = return_gateways_array(false, true);
829
	if (!empty($gateways_arr[$name])) {
830
		$interfacegw = $gateways_arr[$name]['friendlyiface'];
831
		return ($interfacegw);
832
	}
833

    
834
	return (false);
835
}
836

    
837
function get_interface_gateway($interface, &$dynamic = false) {
838
	global $config, $g;
839

    
840
	$gw = NULL;
841

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

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

    
862
	}
863

    
864
	/* return gateway */
865
	return ($gw);
866
}
867

    
868
function get_interface_gateway_v6($interface, &$dynamic = false) {
869
	global $config, $g;
870

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

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

    
892
	}
893
	/* return gateway */
894
	return ($gw);
895
}
896

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

    
905
	if(is_ipaddrv4($ipaddr))
906
		$v4ip = true;
907
	if(is_ipaddrv6($ipaddr))
908
		$v6ip = true;
909
	if(is_ipaddrv4($gwname))
910
		$v4gw = true;
911
	if(is_ipaddrv6($gwname))
912
		$v6gw = true;
913

    
914
	if($v4ip && $v4gw)
915
		return true;
916
	if($v6ip && $v6gw)
917
		return true;
918

    
919
	/* still no match, carry on, lookup gateways */
920
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
921
		$v4gw = true;
922
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
923
		$v6gw = true;
924

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

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

    
942
	return false;
943
}
944

    
945
/* check if a interface is part of a gateway group */
946
function interface_gateway_group_member($interface) {
947
	global $config;
948

    
949
	if (is_array($config['gateways']['gateway_group']))
950
		$groups = $config['gateways']['gateway_group'];
951
	else
952
		return false;
953

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

    
969
	return false;
970
}
971

    
972
function gateway_is_gwgroup_member($name) {
973
	global $config;
974

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

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

    
992
	return $members;
993
}
994
?>
(24-24/66)