Project

General

Profile

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

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

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

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

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

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

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

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

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

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

    
60
	$apinger_default = return_apinger_defaults();
61
	$apingerconfig = <<<EOD
62

    
63
# pfSense apinger configuration file. Automatically Generated!
64

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
142
EOD;
143

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

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

    
160
		/* Interface ip is needed since apinger will bind a socket to it. */
161
		if (is_ipaddrv4($gateway['gateway'])) {
162
			$gwifip = find_interface_ip($gateway['interface'], true);
163
			if (!is_ipaddrv4($gwifip))
164
				continue; //Skip this target
165

    
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, $inactive = false) {
363
	global $config, $g;
364

    
365
	$gateways_arr = array();
366

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

    
370
	// Ensure the interface cache is up to date first
371
	$interfaces = get_interface_arr(true);
372
	$interfaces_v4 = array();
373
	$interfaces_v6 = array();
374

    
375
	$i = -1;
376
	/* Process/add all the configured gateways. */
377
	if (is_array($config['gateways']['gateway_item'])) {
378
		foreach ($config['gateways']['gateway_item'] as $gateway) {
379
			/* Increment it here to do not skip items */
380
			$i++;
381

    
382
			if (empty($config['interfaces'][$gateway['interface']])) {
383
				if ($inactive === false)
384
					continue;
385
				else
386
					$gateway['inactive'] = true;
387
			}
388
			$wancfg = $config['interfaces'][$gateway['interface']];
389

    
390
			/* skip disabled interfaces */
391
			if ($disabled === false && (!isset($wancfg['enable']) || !isset($gateway['disabled'])))
392
				continue;
393

    
394
			/* if the gateway is dynamic and we can find the IPv4, Great! */
395
			if (empty($gateway['gateway']) || $gateway['gateway'] == "dynamic" || $gateway['gateway'] == "dynamic6") {
396
				if ($gateway['ipprotocol'] == "inet") {
397
					/* we know which interfaces is dynamic, this should be made a function */
398
					$gateway['ipprotocol'] = "inet";
399
					$gateway['gateway'] = get_interface_gateway($gateway['interface']);
400
					/* no IP address found, set to dynamic */
401
					if (!is_ipaddrv4($gateway['gateway']))
402
						$gateway['gateway'] = "dynamic";
403
					$gateway['dynamic'] = true;
404
				}
405

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

    
425
			if (isset($gateway['monitor_disable']))
426
				$gateway['monitor_disable'] = true;
427
			else if (empty($gateway['monitor']))
428
				$gateway['monitor'] = $gateway['gateway'];
429

    
430
			$gateway['friendlyiface'] = $gateway['interface'];
431

    
432
			/* special treatment for tunnel interfaces */
433
			if ($gateway['ipprotocol'] == "inet6") {
434
				$gateway['interface'] = get_real_interface($gateway['interface'], "inet6", false, false);
435
				$interfaces_v6[$gateway['friendlyiface']] = $gateway['friendlyiface'];
436
			} else {
437
				$gateway['interface'] = get_real_interface($gateway['interface'], "all", false, false);
438
				$interfaces_v4[$gateway['friendlyiface']] = $gateway['friendlyiface'];
439
			}
440

    
441
			/* entry has a default flag, use it */
442
			if (isset($gateway['defaultgw'])) {
443
				if ($gateway['ipprotocol'] == "inet") {
444
					$gateway['defaultgw'] = true;
445
					$found_defaultv4 = 1;
446
				} else if ($gateway['ipprotocol'] == "inet6") {
447
					$gateway['defaultgw'] = true;
448
					$found_defaultv6 = 1;
449
				}
450
			}
451
			/* include the gateway index as the attribute */
452
			$gateway['attribute'] = $i;
453

    
454
			$gateways_arr[$gateway['name']] = $gateway;
455
		}
456
	}
457
	unset($gateway);
458

    
459
	/* Loop through all interfaces with a gateway and add it to a array */
460
	if ($disabled == false)
461
		$iflist = get_configured_interface_with_descr();
462
	else
463
		$iflist = get_configured_interface_with_descr(false, true);
464

    
465
	/* Process/add dynamic v4 gateways. */
466
	foreach($iflist as $ifname => $friendly ) {
467
		if(! interface_has_gateway($ifname))
468
			continue;
469

    
470
		if (empty($config['interfaces'][$ifname]))
471
			continue;
472

    
473
		$ifcfg = &$config['interfaces'][$ifname];
474
		if(!isset($ifcfg['enable']))
475
			continue;
476

    
477
		if(!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr']))
478
			continue;
479

    
480
		if (isset($interfaces_v4[$ifname]))
481
			continue;
482

    
483
		$ctype = "";
484
		switch($ifcfg['ipaddr']) {
485
			case "dhcp":
486
			case "pppoe":
487
			case "pptp":
488
			case "ppp":
489
				$ctype = strtoupper($ifcfg['ipaddr']);
490
				break;
491
			default:
492
				if (substr($ifcfg['if'], 0, 4) ==  "ovpn")
493
					$ctype = "VPNv4";
494
				break;
495
		}
496
		$ctype = "_". strtoupper($ctype);
497

    
498
		$gateway = array();
499
		$gateway['dynamic'] = false;
500
		$gateway['ipprotocol'] = "inet";
501
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
502
		$gateway['interface'] = get_real_interface($ifname);
503
		$gateway['friendlyiface'] = $ifname;
504
		$gateway['name'] = "{$friendly}{$ctype}";
505
		$gateway['attribute'] = "system";
506

    
507
		if (($gateway['dynamic'] === "default") && ($found_defaultv4 == 0)) {
508
			$gateway['defaultgw'] = true;
509
			$gateway['dynamic'] = true;
510
			$found_defaultv4 = 1;
511
		}
512
		/* Loopback dummy for dynamic interfaces without a IP */
513
		if (!is_ipaddrv4($gateway['gateway']) && $gateway['dynamic'] == true)
514
			$gateway['gateway'] = "dynamic";
515

    
516
		/* automatically skip known static and dynamic gateways we have a array entry for */
517
		foreach($gateways_arr as $gateway_item) {
518
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name'])&& ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
519
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
520
					continue 2;
521
		}
522

    
523
		if (is_ipaddrv4($gateway['gateway']))
524
			$gateway['monitor'] = $gateway['gateway'];
525

    
526
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
527
		$gateways_arr[$gateway['name']] = $gateway;
528
	}
529
	unset($gateway);
530

    
531
	/* Process/add dynamic v6 gateways. */
532
	foreach($iflist as $ifname => $friendly ) {
533
		/* If the user has disabled IPv6, they probably don't want any IPv6 gateways. */
534
		if (!isset($config['system']['ipv6allow']))
535
			break;
536

    
537
		if(! interface_has_gatewayv6($ifname))
538
			continue;
539

    
540
		if (empty($config['interfaces'][$ifname]))
541
			continue;
542

    
543
		$ifcfg = &$config['interfaces'][$ifname];
544
		if(!isset($ifcfg['enable']))
545
			continue;
546

    
547
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
548
			continue;
549

    
550
		if(isset($interfaces_v6[$ifname]))
551
			continue;
552

    
553
		$ctype = "";
554
		switch($ifcfg['ipaddrv6']) {
555
			case "slaac":
556
			case "dhcp6":
557
			case "6to4":
558
			case "6rd":
559
				$ctype = strtoupper($ifcfg['ipaddrv6']);
560
				break;
561
			default:
562
				if (substr($ifcfg['if'], 0, 4) ==  "ovpn")
563
					$ctype = "VPNv6";
564
				break;
565
		}
566
		$ctype = "_". strtoupper($ctype);
567

    
568
		$gateway = array();
569
		$gateway['dynamic'] = false;
570
		$gateway['ipprotocol'] = "inet6";
571
		$gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
572
		$gateway['interface'] = get_real_interface($ifname, "inet6");
573
		switch($ifcfg['ipaddrv6']) {
574
			case "6rd":
575
			case "6to4":
576
				$gateway['dynamic'] = "default";
577
				break;
578
		}
579
		$gateway['friendlyiface'] = $ifname;
580
		$gateway['name'] = "{$friendly}{$ctype}";
581
		$gateway['attribute'] = "system";
582

    
583
		if (($gateway['dynamic'] === "default")  && ($found_defaultv6 == 0)) {
584
			$gateway['defaultgw'] = true;
585
			$gateway['dynamic'] = true;
586
			$found_defaultv6 = 1;
587
		}
588

    
589
		/* Loopback dummy for dynamic interfaces without a IP */
590
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
591
			$gateway['gateway'] = "dynamic6";
592

    
593
		/* automatically skip known static and dynamic gateways we have a array entry for */
594
		foreach($gateways_arr as $gateway_item) {
595
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
596
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
597
					continue 2;
598
		}
599

    
600
		if (is_ipaddrv6($gateway['gateway']))
601
			$gateway['monitor'] = $gateway['gateway'];
602

    
603
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
604
		$gateways_arr[$gateway['name']] = $gateway;
605
	}
606
	unset($gateway);
607

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

    
629
	if($localhost === true) {
630
		/* attach localhost for Null routes */
631
		$gwlo4 = array();
632
		$gwlo4['name'] = "Null4";
633
		$gwlo4['interface'] = "lo0";
634
		$gwlo4['ipprotocol'] = "inet";
635
		$gwlo4['gateway'] = "127.0.0.1";
636
		$gwlo6 = array();
637
		$gwlo6['name'] = "Null6";
638
		$gwlo6['interface'] = "lo0";
639
		$gwlo6['ipprotocol'] = "inet6";
640
		$gwlo6['gateway'] = "::1";
641
		$gateways_arr['Null4'] = $gwlo4;
642
		$gateways_arr['Null6'] = $gwlo6;
643
	}
644
	return($gateways_arr);
645
}
646

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

    
699
/*
700
 * Return an array with all gateway groups with name as key
701
 * All gateway groups will be processed before returning the array.
702
 */
703
function return_gateway_groups_array() {
704
	global $config, $g;
705

    
706
	/* fetch the current gateways status */
707
	$gateways_status = return_gateways_status(true);
708
	$gateways_arr = return_gateways_array();
709
	$gateway_groups_array = array();
710

    
711
	if (isset($config['system']['gw_switch_default'])) {
712
		fixup_default_gateway("inet", $gateways_status, $gateways_arr);
713
		fixup_default_gateway("inet6", $gateways_status, $gateways_arr);
714
	}
715
	if (is_array($config['gateways']['gateway_group'])) {
716
		$carplist = get_configured_carp_interface_list();
717
		foreach ($config['gateways']['gateway_group'] as $group) {
718
			/* create array with group gateways members separated by tier */
719
			$tiers = array();
720
			$backupplan = array();
721
			$gwvip_arr = array();
722
			foreach ($group['item'] as $item) {
723
				list($gwname, $tier, $vipname) = explode("|", $item);
724

    
725
				if (is_ipaddr($carplist[$vipname])) {
726
					if (!is_array($gwvip_arr[$group['name']]))
727
						$gwvip_arr[$group['name']] = array();
728
					$gwvip_arr[$group['name']][$gwname] = $vipname;
729
				}
730

    
731
				/* Do it here rather than reiterating again the group in case no member is up. */
732
				if (!is_array($backupplan[$tier]))
733
					$backupplan[$tier] = array();
734
				$backupplan[$tier][] = $gwname;
735

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

    
779
			/* we do not really foreach the tiers as we stop after the first tier */
780
			foreach ($tiers as $tieridx => $tier) {
781
				/* process all gateways in this tier */
782
				foreach ($tier as $member) {
783
					/* determine interface gateway */
784
					if (isset($gateways_arr[$member])) {
785
						$gateway = $gateways_arr[$member];
786
						$int = $gateway['interface'];
787
						$gatewayip = "";
788
						if(is_ipaddr($gateway['gateway']))
789
							$gatewayip = $gateway['gateway'];
790
						else if (!empty($int))
791
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
792

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

    
814
	return ($gateway_groups_array);
815
}
816

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

    
833
function lookup_gateway_ip_by_name($name) {
834

    
835
	$gateways_arr = return_gateways_array(false, true);
836
	foreach ($gateways_arr as $gname => $gw) {
837
		if ($gw['name'] === $name || $gname === $name)
838
			return $gw['gateway'];
839
	}
840

    
841
	return false;
842
}
843

    
844
function lookup_gateway_monitor_ip_by_name($name) {
845

    
846
	$gateways_arr = return_gateways_array(false, true);
847
	if (!empty($gateways_arr[$name])) {
848
		$gateway = $gateways_arr[$name];
849
		if(!is_ipaddr($gateway['monitor']))
850
			return $gateway['gateway'];
851

    
852
		return $gateway['monitor'];
853
	}
854

    
855
	return (false);
856
}
857

    
858
function lookup_gateway_interface_by_name($name) {
859

    
860
	$gateways_arr = return_gateways_array(false, true);
861
	if (!empty($gateways_arr[$name])) {
862
		$interfacegw = $gateways_arr[$name]['friendlyiface'];
863
		return ($interfacegw);
864
	}
865

    
866
	return (false);
867
}
868

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

    
872
	$gw = NULL;
873

    
874
	$gwcfg = $config['interfaces'][$interface];
875
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
876
		foreach($config['gateways']['gateway_item'] as $gateway) {
877
			if(($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
878
				$gw = $gateway['gateway'];
879
				break;
880
			}
881
		}
882
	}
883

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

    
894
	}
895

    
896
	/* return gateway */
897
	return ($gw);
898
}
899

    
900
function get_interface_gateway_v6($interface, &$dynamic = false) {
901
	global $config, $g;
902

    
903
	$gw = NULL;
904
	$gwcfg = $config['interfaces'][$interface];
905
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
906
		foreach($config['gateways']['gateway_item'] as $gateway) {
907
			if(($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
908
				$gw = $gateway['gateway'];
909
				break;
910
			}
911
		}
912
	}
913

    
914
	// for dynamic interfaces we handle them through the $interface_router file.
915
	if (!is_ipaddrv6($gw) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
916
			$realif = get_real_interface($interface);
917
			if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
918
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
919
				$dynamic = true;
920
			}
921
			if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6"))
922
				$dynamic = "default";
923

    
924
	}
925
	/* return gateway */
926
	return ($gw);
927
}
928

    
929
/* Check a IP address against a gateway IP or name
930
 * to verify it's address family */
931
function validate_address_family($ipaddr, $gwname) {
932
	$v4ip = false;
933
	$v6ip = false;
934
	$v4gw = false;
935
	$v6gw = false;
936

    
937
	if(is_ipaddrv4($ipaddr))
938
		$v4ip = true;
939
	if(is_ipaddrv6($ipaddr))
940
		$v6ip = true;
941
	if(is_ipaddrv4($gwname))
942
		$v4gw = true;
943
	if(is_ipaddrv6($gwname))
944
		$v6gw = true;
945

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

    
951
	/* still no match, carry on, lookup gateways */
952
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
953
		$v4gw = true;
954
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
955
		$v6gw = true;
956

    
957
	$gw_array = return_gateways_array();
958
	if(is_array($gw_array[$gwname])) {
959
		switch($gw_array[$gwname]['ipprotocol']) {
960
			case "inet":
961
				$v4gw = true;
962
				break;
963
			case "inet6":
964
				$v6gw = true;
965
				break;
966
		}
967
	}
968

    
969
	if($v4ip && $v4gw)
970
		return true;
971
	if($v6ip && $v6gw)
972
		return true;
973

    
974
	return false;
975
}
976

    
977
/* check if a interface is part of a gateway group */
978
function interface_gateway_group_member($interface) {
979
	global $config;
980

    
981
	if (is_array($config['gateways']['gateway_group']))
982
		$groups = $config['gateways']['gateway_group'];
983
	else
984
		return false;
985

    
986
	$gateways_arr = return_gateways_array(false, true);
987
	foreach($groups as $group) {
988
		if(is_array($group['item'])) {
989
			foreach($group['item'] as $item) {
990
				$elements = explode("|", $item);
991
				$gwname = $elements[0];
992
				if ($interface == $gateways_arr[$gwname]['interface']) {
993
					unset($gateways_arr);
994
					return true;
995
				}
996
			}
997
		}
998
	}
999
	unset($gateways_arr);
1000

    
1001
	return false;
1002
}
1003

    
1004
function gateway_is_gwgroup_member($name) {
1005
	global $config;
1006

    
1007
	if (is_array($config['gateways']['gateway_group']))
1008
		$groups = $config['gateways']['gateway_group'];
1009
	else
1010
		return false;
1011

    
1012
	$members = array();
1013
	foreach($groups as $group) {
1014
		if (is_array($group['item'])) {
1015
			foreach($group['item'] as $item) {
1016
				$elements = explode("|", $item);
1017
				$gwname = $elements[0];
1018
				if ($name == $elements[0])
1019
					$members[] = $group['name'];
1020
			}
1021
		}
1022
	}
1023

    
1024
	return $members;
1025
}
1026
?>
(24-24/66)