Projet

Général

Profil

Télécharger (36,5 ko) Statistiques
| Branche: | Tag: | Révision:

univnautes / etc / inc / gwlb.inc @ b22f436a

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
require_once("rrd.inc");
34

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

    
49
/*
50
 * Creates monitoring configuration file and
51
 * adds appropriate static routes.
52
 */
53
function setup_gateways_monitor() {
54
	global $config, $g;
55

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

    
64
	$apinger_debug = "";
65
	if (isset($config['system']['apinger_debug']))
66
		$apinger_debug = "debug on";
67

    
68
	$apinger_default = return_apinger_defaults();
69
	$apingerconfig = <<<EOD
70

    
71
# pfSense apinger configuration file. Automatically Generated!
72

    
73
{$apinger_debug}
74

    
75
## User and group the pinger should run as
76
user "root"
77
group "wheel"
78

    
79
## Mailer to use (default: "/usr/lib/sendmail -t")
80
#mailer "/var/qmail/bin/qmail-inject"
81

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

    
85
## Format of timestamp (%s macro) (default: "%b %d %H:%M:%S")
86
#timestamp_format "%Y%m%d%H%M%S"
87

    
88
status {
89
	## File where the status information should be written to
90
	file "{$g['varrun_path']}/apinger.status"
91
	## Interval between file updates
92
	## when 0 or not set, file is written only when SIGUSR1 is received
93
	interval 5s
94
}
95

    
96
########################################
97
# RRDTool status gathering configuration
98
# Interval between RRD updates
99
rrd interval 60s;
100

    
101
## These parameters can be overridden in a specific alarm configuration
102
alarm default {
103
	command on "/usr/local/sbin/pfSctl -c 'service reload dyndns %T' -c 'service reload ipsecdns' -c 'service reload openvpn %T' -c 'filter reload' "
104
	command off "/usr/local/sbin/pfSctl -c 'service reload dyndns %T' -c 'service reload ipsecdns' -c 'service reload openvpn %T' -c 'filter reload' "
105
	combine 10s
106
}
107

    
108
## "Down" alarm definition.
109
## This alarm will be fired when target doesn't respond for 30 seconds.
110
alarm down "down" {
111
	time {$apinger_default['down']}s
112
}
113

    
114
## "Delay" alarm definition.
115
## This alarm will be fired when responses are delayed more than 200ms
116
## it will be canceled, when the delay drops below 100ms
117
alarm delay "delay" {
118
	delay_low {$apinger_default['latencylow']}ms
119
	delay_high {$apinger_default['latencyhigh']}ms
120
}
121

    
122
## "Loss" alarm definition.
123
## This alarm will be fired when packet loss goes over 20%
124
## it will be canceled, when the loss drops below 10%
125
alarm loss "loss" {
126
	percent_low {$apinger_default['losslow']}
127
	percent_high {$apinger_default['losshigh']}
128
}
129

    
130
target default {
131
	## How often the probe should be sent
132
	interval {$apinger_default['interval']}s
133

    
134
	## How many replies should be used to compute average delay
135
	## for controlling "delay" alarms
136
	avg_delay_samples {$apinger_default['avg_delay_samples']}
137

    
138
	## How many probes should be used to compute average loss
139
	avg_loss_samples {$apinger_default['avg_loss_samples']}
140

    
141
	## The delay (in samples) after which loss is computed
142
	## without this delays larger than interval would be treated as loss
143
	avg_loss_delay_samples {$apinger_default['avg_loss_delay_samples']}
144

    
145
	## Names of the alarms that may be generated for the target
146
	alarms "down","delay","loss"
147

    
148
	## Location of the RRD
149
	#rrd file "{$g['vardb_path']}/rrd/apinger-%t.rrd"
150
}
151

    
152
EOD;
153

    
154
	$monitor_ips = array();
155
	foreach($gateways_arr as $name => $gateway) {
156
		/* Do not monitor if such was requested */
157
		if (isset($gateway['monitor_disable']))
158
			continue;
159
		if (empty($gateway['monitor']) || !is_ipaddr($gateway['monitor'])) {
160
			if (is_ipaddr($gateway['gateway']))
161
				$gateway['monitor'] = $gateway['gateway'];
162
			else /* No chance to get an ip to monitor skip target. */
163
				continue;
164
		}
165

    
166
		/* if the monitor address is already used before, skip */
167
		if(in_array($gateway['monitor'], $monitor_ips))
168
			continue;
169

    
170
		/* Interface ip is needed since apinger will bind a socket to it. 
171
		 * However the config GUI should already have checked this and when 
172
		 * PPoE is used the IP address is set to "dynamic". So using is_ipaddrv4
173
		 * or is_ipaddrv6 to identify packet type would be wrong, especially as
174
		 * further checks (that can cope with the "dynamic" case) are present inside
175
		 * the if block. So using $gateway['ipprotocol'] is the better option.
176
		 */
177
		if ($gateway['ipprotocol'] == "inet") { // This is an IPv4 gateway...
178
			$gwifip = find_interface_ip($gateway['interface'], true);
179
			if (!is_ipaddrv4($gwifip))
180
				continue; //Skip this target
181

    
182
			/*
183
			 * If the gateway is the same as the monitor we do not add a
184
			 * route as this will break the routing table.
185
			 * Add static routes for each gateway with their monitor IP
186
			 * not strictly necessary but is a added level of protection.
187
			 */
188
			if (is_ipaddrv4($gateway['gateway']) && $gateway['monitor'] != $gateway['gateway']) {
189
				log_error("Removing static route for monitor {$gateway['monitor']} and adding a new route through {$gateway['gateway']}");
190
				mwexec("/sbin/route change -host " . escapeshellarg($gateway['monitor']) .
191
					" " . escapeshellarg($gateway['gateway']), true);
192
			}
193
		} else if ($gateway['ipprotocol'] == "inet6") { // This is an IPv6 gateway...
194
			if ($gateway['monitor'] == $gateway['gateway']) {
195
				/* link locals really need a different src ip */
196
				if (is_linklocal($gateway['gateway'])) {
197
					$gwifip = find_interface_ipv6_ll($gateway['interface'], true);
198
				} else {
199
					$gwifip = find_interface_ipv6($gateway['interface'], true);
200
				}
201
			} else {
202
				/* 'monitor' has been set, so makes sure it has precedence over
203
				 * 'gateway' in defining the source IP. Otherwise if 'gateway'
204
				 * is a local link and 'monitor' is global routable then the
205
				 * ICMP6 response would not find its way back home...
206
				 */
207
				$gwifip = find_interface_ipv6($gateway['interface'], true);
208
				if (is_linklocal($gateway['monitor'])) {
209
					if (!strstr($gateway['monitor'], '%')) {
210
						$gateway['monitor'] .= "%{$gateway['interface']}";
211
					}
212
				} else {
213
					// Monitor is a routable address, so use a routable address for the "src" part
214
					$gwifip = find_interface_ipv6($gateway['interface'], true);
215
				}
216
			}
217
							
218
			if (!is_ipaddrv6($gwifip))
219
				continue; //Skip this target
220

    
221
			/*
222
			 * If the gateway is the same as the monitor we do not add a
223
			 * route as this will break the routing table.
224
			 * Add static routes for each gateway with their monitor IP
225
			 * not strictly necessary but is a added level of protection.
226
			 */
227
			if (is_ipaddrv6($gateway['gateway']) && $gateway['monitor'] != $gateway['gateway']) {
228
				log_error("Removing static route for monitor {$gateway['monitor']} and adding a new route through {$gateway['gateway']}");
229
				mwexec("/sbin/route change -host -inet6 " . escapeshellarg($gateway['monitor']) .
230
					" " . escapeshellarg($gateway['gateway']), true);
231
			}
232
		} else
233
			continue;
234

    
235
		$monitor_ips[] = $gateway['monitor'];
236
		$apingercfg = "target \"{$gateway['monitor']}\" {\n";
237
		$apingercfg .= "	description \"{$name}\"\n";
238
		$apingercfg .= "	srcip \"{$gwifip}\"\n";
239

    
240
		## How often the probe should be sent
241
		if (!empty($gateway['interval']) &&  is_numeric($gateway['interval'])) {
242
			$interval = intval($gateway['interval']);	# Restrict to Integer
243
			if ($interval <  1) $interval =  1;	# Minimum
244
			if ($interval != $apinger_default['interval'])	# If not default value
245
				$apingercfg .= "	interval " . $interval . "s\n";
246
		}
247

    
248
		## How many replies should be used to compute average delay 
249
		## for controlling "delay" alarms
250
		if (!empty($gateway['avg_delay_samples']) && is_numeric($gateway['avg_delay_samples'])) {
251
			$avg_delay_samples = intval($gateway['avg_delay_samples']);	# Restrict to Integer
252
			if ($avg_delay_samples <  1) $avg_delay_samples =  1;	# Minimum
253
			if ($avg_delay_samples != $apinger_default['avg_delay_samples'])	# If not default value
254
				$apingercfg .= "	avg_delay_samples " . $avg_delay_samples . "\n";
255
		}
256

    
257
		## How many probes should be used to compute average loss
258
		if (!empty($gateway['avg_loss_samples']) && is_numeric($gateway['avg_loss_samples'])) {
259
			$avg_loss_samples = intval($gateway['avg_loss_samples']);	# Restrict to Integer
260
			if ($avg_loss_samples < 1) $avg_loss_samples = 1;	# Minimum
261
			if ($avg_loss_samples != $apinger_default['avg_loss_samples'])	# If not default value
262
				$apingercfg .= "	avg_loss_samples " . $avg_loss_samples . "\n";
263
		}
264

    
265
		## The delay (in samples) after which loss is computed
266
		## without this delays larger than interval would be treated as loss
267
		if (!empty($gateway['avg_loss_delay_samples']) && is_numeric($gateway['avg_loss_delay_samples'])) {
268
			$avg_loss_delay_samples = intval($gateway['avg_loss_delay_samples']);	# Restrict to Integer
269
			if ($avg_loss_delay_samples < 1) $avg_loss_delay_samples = 1;	# Minimum
270
			if ($avg_loss_delay_samples != $apinger_default['avg_loss_delay_samples'])	# If not default value
271
				$apingercfg .= "	avg_loss_delay_samples " . $avg_loss_delay_samples . "\n";
272
		}
273

    
274
		$alarms = "";
275
		$alarmscfg = "";
276
		$override = false;
277
		if (!empty($gateway['losslow'])) {
278
			$alarmscfg .= "alarm loss \"{$name}loss\" {\n";
279
			$alarmscfg .= "\tpercent_low {$gateway['losslow']}\n";
280
			$alarmscfg .= "\tpercent_high {$gateway['losshigh']}\n";
281
			$alarmscfg .= "}\n";
282
			$alarms .= "\"{$name}loss\"";
283
			$override = true;
284
		} else {
285
			if ($override == true)
286
				$alarms .= ",";
287
			$alarms .= "\"loss\"";
288
			$override = true;
289
		}
290
		if (!empty($gateway['latencylow'])) {
291
			$alarmscfg .= "alarm delay \"{$name}delay\" {\n";
292
			$alarmscfg .= "\tdelay_low {$gateway['latencylow']}ms\n";
293
			$alarmscfg .= "\tdelay_high {$gateway['latencyhigh']}ms\n";
294
			$alarmscfg .= "}\n";
295
			if ($override == true)
296
				$alarms .= ",";
297
			$alarms .= "\"{$name}delay\"";
298
			$override = true;
299
		} else {
300
			if ($override == true)
301
				$alarms .= ",";
302
			$alarms .= "\"delay\"";
303
			$override = true;
304
		}
305
		if (!empty($gateway['down'])) {
306
			$alarmscfg .= "alarm down \"{$name}down\" {\n";
307
			$alarmscfg .= "\ttime {$gateway['down']}s\n";
308
			$alarmscfg .= "}\n";
309
			if ($override == true)
310
				$alarms .= ",";
311
			$alarms .= "\"{$name}down\"";
312
			$override = true;
313
		} else {
314
			if ($override == true)
315
				$alarms .= ",";
316
			$alarms .= "\"down\"";
317
			$override = true;
318
		}
319
		if ($override == true)
320
			$apingercfg .= "\talarms override {$alarms};\n";
321

    
322
		if (isset($gateway['force_down']))
323
			$apingercfg .= "\tforce_down on\n";
324

    
325
		$apingercfg .= "	rrd file \"{$g['vardb_path']}/rrd/{$gateway['name']}-quality.rrd\"\n";
326
		$apingercfg .= "}\n";
327
		$apingercfg .= "\n";
328

    
329
		$apingerconfig .= $alarmscfg;
330
		$apingerconfig .= $apingercfg;
331

    
332
		# Create gateway quality RRD with settings more suitable for pfSense graph set, 
333
		# since apinger uses default step (300; 5 minutes) and other settings that don't 
334
		# match the pfSense gateway quality graph set.
335
		create_gateway_quality_rrd("{$g['vardb_path']}/rrd/{$gateway['name']}-quality.rrd");
336
	}
337
	@file_put_contents("{$g['varetc_path']}/apinger.conf", $apingerconfig);
338
	unset($apingerconfig);
339

    
340
	if (is_dir("{$g['tmp_path']}"))
341
		chmod("{$g['tmp_path']}", 01777);
342
	if (!is_dir("{$g['vardb_path']}/rrd"))
343
		mkdir("{$g['vardb_path']}/rrd", 0775);
344

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

    
347
 	/* Restart apinger process */
348
	if (isvalidpid("{$g['varrun_path']}/apinger.pid"))
349
		sigkillbypid("{$g['varrun_path']}/apinger.pid", "HUP");
350
	else {
351
		/* start a new apinger process */
352
		@unlink("{$g['varrun_path']}/apinger.status");
353
		sleep(1);
354
		mwexec_bg("/usr/local/sbin/apinger -c {$g['varetc_path']}/apinger.conf");
355
		sleep(1);
356
		sigkillbypid("{$g['varrun_path']}/apinger.pid", "USR1");
357
	}
358

    
359
	return 0;
360
}
361

    
362
/* return the status of the apinger targets as a array */
363
function return_gateways_status($byname = false) {
364
	global $config, $g;
365

    
366
	$apingerstatus = array();
367
	/* Always get the latest status from apinger */
368
	if (file_exists("{$g['varrun_path']}/apinger.pid"))
369
                sigkillbypid("{$g['varrun_path']}/apinger.pid", "USR1");
370
	if (file_exists("{$g['varrun_path']}/apinger.status")) {
371
		$apingerstatus = file("{$g['varrun_path']}/apinger.status");
372
	} else
373
		$apingerstatus = array();
374

    
375
	$status = array();
376
	foreach($apingerstatus as $line) {
377
		$info = explode("|", $line);
378
		if ($byname == false)
379
			$target = $info[0];
380
		else
381
			$target = $info[2];
382

    
383
		$status[$target] = array();
384
		$status[$target]['monitorip'] = $info[0];
385
		$status[$target]['srcip'] = $info[1];
386
		$status[$target]['name'] = $info[2];
387
		$status[$target]['lastcheck'] = $info[5] ? date('r', $info[5]) : date('r');
388
		$status[$target]['delay'] = empty($info[6]) ? "0ms" : round($info[6], 1) ."ms" ;
389
		$status[$target]['loss'] = empty($info[7]) ? "0.0%" : round($info[7], 1) . "%";
390
		$status[$target]['status'] = trim($info[8]);
391
	}
392

    
393
	/* tack on any gateways that have monitoring disabled
394
	 * or are down, which could cause gateway groups to fail */
395
	$gateways_arr = return_gateways_array();
396
	foreach($gateways_arr as $gwitem) {
397
		if(!isset($gwitem['monitor_disable']))
398
			continue;
399
		if(!is_ipaddr($gwitem['monitorip'])) {
400
			$realif = $gwitem['interface'];
401
			$tgtip = get_interface_gateway($realif);
402
			if (!is_ipaddr($tgtip))
403
				$tgtip = "none";
404
			$srcip = find_interface_ip($realif);
405
		} else {
406
			$tgtip = $gwitem['monitorip'];
407
			$srcip = find_interface_ip($realif);
408
		}
409
		if($byname == true)
410
			$target = $gwitem['name'];
411
		else
412
			$target = $tgtip;
413

    
414
		/* failsafe for down interfaces */
415
		if($target == "none") {
416
			$target = $gwitem['name'];
417
			$status[$target]['name'] = $gwitem['name'];
418
			$status[$target]['lastcheck'] = date('r');
419
			$status[$target]['delay'] = "0.0ms";
420
			$status[$target]['loss'] = "100.0%";
421
			$status[$target]['status'] = "down";
422
		} else {
423
			$status[$target]['monitorip'] = $tgtip;
424
			$status[$target]['srcip'] = $srcip;
425
			$status[$target]['name'] = $gwitem['name'];
426
			$status[$target]['lastcheck'] = date('r');
427
			$status[$target]['delay'] = "0.0ms";
428
			$status[$target]['loss'] = "0.0%";
429
			$status[$target]['status'] = "none";
430
		}
431
	}
432
	return($status);
433
}
434

    
435
/* Return all configured gateways on the system */
436
function return_gateways_array($disabled = false, $localhost = false, $inactive = false) {
437
	global $config, $g;
438

    
439
	$gateways_arr = array();
440

    
441
	$found_defaultv4 = 0;
442
	$found_defaultv6 = 0;
443

    
444
	// Ensure the interface cache is up to date first
445
	$interfaces = get_interface_arr(true);
446
	$interfaces_v4 = array();
447
	$interfaces_v6 = array();
448

    
449
	$i = -1;
450
	/* Process/add all the configured gateways. */
451
	if (is_array($config['gateways']['gateway_item'])) {
452
		foreach ($config['gateways']['gateway_item'] as $gateway) {
453
			/* Increment it here to do not skip items */
454
			$i++;
455

    
456
			if (empty($config['interfaces'][$gateway['interface']])) {
457
				if ($inactive === false)
458
					continue;
459
				else
460
					$gateway['inactive'] = true;
461
			}
462
			$wancfg = $config['interfaces'][$gateway['interface']];
463

    
464
			/* skip disabled interfaces */
465
			if ($disabled === false && (!isset($wancfg['enable']) || isset($gateway['disabled'])))
466
				continue;
467

    
468
			/* if the gateway is dynamic and we can find the IPv4, Great! */
469
			if (empty($gateway['gateway']) || $gateway['gateway'] == "dynamic") {
470
				if ($gateway['ipprotocol'] == "inet") {
471
					/* we know which interfaces is dynamic, this should be made a function */
472
					$gateway['gateway'] = get_interface_gateway($gateway['interface']);
473
					/* no IP address found, set to dynamic */
474
					if (!is_ipaddrv4($gateway['gateway']))
475
						$gateway['gateway'] = "dynamic";
476
					$gateway['dynamic'] = true;
477
				}
478

    
479
				/* if the gateway is dynamic and we can find the IPv6, Great! */
480
				else if ($gateway['ipprotocol'] == "inet6") {
481
					/* we know which interfaces is dynamic, this should be made a function, and for v6 too */
482
					$gateway['gateway'] = get_interface_gateway_v6($gateway['interface']);
483
					/* no IPv6 address found, set to dynamic */
484
					if (!is_ipaddrv6($gateway['gateway']))
485
						$gateway['gateway'] = "dynamic";
486
					$gateway['dynamic'] = true;
487
				}
488
			} else {
489
				/* getting this detection right is hard at this point because we still don't
490
				 * store the address family in the gateway item */
491
				if (is_ipaddrv4($gateway['gateway']))
492
					$gateway['ipprotocol'] = "inet";
493
				else if(is_ipaddrv6($gateway['gateway']))
494
					$gateway['ipprotocol'] = "inet6";
495
			}
496

    
497
			if (isset($gateway['monitor_disable']))
498
				$gateway['monitor_disable'] = true;
499
			else if (empty($gateway['monitor']))
500
				$gateway['monitor'] = $gateway['gateway'];
501

    
502
			$gateway['friendlyiface'] = $gateway['interface'];
503

    
504
			/* special treatment for tunnel interfaces */
505
			if ($gateway['ipprotocol'] == "inet6") {
506
				$gateway['interface'] = get_real_interface($gateway['interface'], "inet6", false, false);
507
				$interfaces_v6[$gateway['friendlyiface']] = $gateway['friendlyiface'];
508
			} else {
509
				$gateway['interface'] = get_real_interface($gateway['interface'], "all", false, false);
510
				$interfaces_v4[$gateway['friendlyiface']] = $gateway['friendlyiface'];
511
			}
512

    
513
			/* entry has a default flag, use it */
514
			if (isset($gateway['defaultgw'])) {
515
				if ($gateway['ipprotocol'] == "inet") {
516
					$gateway['defaultgw'] = true;
517
					$found_defaultv4 = 1;
518
				} else if ($gateway['ipprotocol'] == "inet6") {
519
					$gateway['defaultgw'] = true;
520
					$found_defaultv6 = 1;
521
				}
522
			}
523
			/* include the gateway index as the attribute */
524
			$gateway['attribute'] = $i;
525

    
526
			$gateways_arr[$gateway['name']] = $gateway;
527
		}
528
	}
529
	unset($gateway);
530

    
531
	/* Loop through all interfaces with a gateway and add it to a array */
532
	if ($disabled == false)
533
		$iflist = get_configured_interface_with_descr();
534
	else
535
		$iflist = get_configured_interface_with_descr(false, true);
536

    
537
	/* Process/add dynamic v4 gateways. */
538
	foreach($iflist as $ifname => $friendly ) {
539
		if(! interface_has_gateway($ifname))
540
			continue;
541

    
542
		if (empty($config['interfaces'][$ifname]))
543
			continue;
544

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

    
549
		if(!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr']))
550
			continue;
551

    
552
		if (isset($interfaces_v4[$ifname]))
553
			continue;
554

    
555
		$ctype = "";
556
		switch($ifcfg['ipaddr']) {
557
			case "dhcp":
558
			case "pppoe":
559
			case "pptp":
560
			case "ppp":
561
				$ctype = strtoupper($ifcfg['ipaddr']);
562
				break;
563
			default:
564
				if (substr($ifcfg['if'], 0, 4) ==  "ovpn") {
565
					// if current iface is an ovpn server endpoint then skip it
566
					if (substr($ifcfg['if'], 4, 1) == 's')
567
						continue 2;							
568

    
569
					$ctype = "VPNv4";
570
				}
571
				break;
572
		}
573
		$ctype = "_". strtoupper($ctype);
574

    
575
		$gateway = array();
576
		$gateway['dynamic'] = false;
577
		$gateway['ipprotocol'] = "inet";
578
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
579
		$gateway['interface'] = get_real_interface($ifname);
580
		$gateway['friendlyiface'] = $ifname;
581
		$gateway['name'] = "{$friendly}{$ctype}";
582
		$gateway['attribute'] = "system";
583

    
584
		if (($gateway['dynamic'] === "default") && ($found_defaultv4 == 0)) {
585
			$gateway['defaultgw'] = true;
586
			$gateway['dynamic'] = true;
587
			$found_defaultv4 = 1;
588
		}
589
		/* Loopback dummy for dynamic interfaces without a IP */
590
		if (!is_ipaddrv4($gateway['gateway']) && $gateway['dynamic'] == true)
591
			$gateway['gateway'] = "dynamic";
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_ipaddrv4($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
	/* Process/add dynamic v6 gateways. */
609
	foreach($iflist as $ifname => $friendly ) {
610
		/* If the user has disabled IPv6, they probably don't want any IPv6 gateways. */
611
		if (!isset($config['system']['ipv6allow']))
612
			break;
613

    
614
		if(! interface_has_gatewayv6($ifname))
615
			continue;
616

    
617
		if (empty($config['interfaces'][$ifname]))
618
			continue;
619

    
620
		$ifcfg = &$config['interfaces'][$ifname];
621
		if(!isset($ifcfg['enable']))
622
			continue;
623

    
624
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
625
			continue;
626

    
627
		if(isset($interfaces_v6[$ifname]))
628
			continue;
629

    
630
		$ctype = "";
631
		switch($ifcfg['ipaddrv6']) {
632
			case "slaac":
633
			case "dhcp6":
634
			case "6to4":
635
			case "6rd":
636
				$ctype = strtoupper($ifcfg['ipaddrv6']);
637
				break;
638
			default:
639
				$tunnelif = substr($ifcfg['if'], 0, 3);
640
				if (substr($ifcfg['if'], 0, 4) ==  "ovpn") {
641
					// if current iface is an ovpn server endpoint then skip it
642
					if (substr($ifcfg['if'], 4, 1) == 's') 
643
						continue 2;							
644

    
645
					$ctype = "VPNv6";
646
				} else if ($tunnelif == "gif" || $tunnelif == "gre")
647
					$ctype = "TUNNELv6";
648
				break;
649
		}
650
		$ctype = "_". strtoupper($ctype);
651

    
652
		$gateway = array();
653
		$gateway['dynamic'] = false;
654
		$gateway['ipprotocol'] = "inet6";
655
		$gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
656
		$gateway['interface'] = get_real_interface($ifname, "inet6");
657
		switch($ifcfg['ipaddrv6']) {
658
			case "6rd":
659
			case "6to4":
660
				$gateway['dynamic'] = "default";
661
				break;
662
		}
663
		$gateway['friendlyiface'] = $ifname;
664
		$gateway['name'] = "{$friendly}{$ctype}";
665
		$gateway['attribute'] = "system";
666

    
667
		if (($gateway['dynamic'] === "default")  && ($found_defaultv6 == 0)) {
668
			$gateway['defaultgw'] = true;
669
			$gateway['dynamic'] = true;
670
			$found_defaultv6 = 1;
671
		}
672

    
673
		/* Loopback dummy for dynamic interfaces without a IP */
674
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
675
			$gateway['gateway'] = "dynamic";
676

    
677
		/* automatically skip known static and dynamic gateways we have a array entry for */
678
		foreach($gateways_arr as $gateway_item) {
679
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
680
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
681
					continue 2;
682
		}
683

    
684
		if (is_ipaddrv6($gateway['gateway']))
685
			$gateway['monitor'] = $gateway['gateway'];
686

    
687
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
688
		$gateways_arr[$gateway['name']] = $gateway;
689
	}
690
	unset($gateway);
691

    
692
	/* FIXME: Should this be enabled.
693
	 * Some interface like wan might be default but have no info recorded
694
	 * the config. */
695
	/* this is a fallback if all else fails and we want to get packets out @smos */
696
	if ($found_defaultv4 == 0 || $found_defaultv6 == 0) {
697
		foreach ($gateways_arr as &$gateway) {
698
			if (($gateway['friendlyiface'] == "wan") && ($found_defaultv4 == 0) && (!isset($gateway['ipprotocol']) || ($gateway['ipprotocol'] == "inet"))) {
699
				if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgw")) {
700
					$gateway['defaultgw'] = true;
701
					$found_defaultv4 = 1;
702
				}
703
			}
704
			if (($gateway['friendlyiface'] == "wan") && ($found_defaultv6 == 0) && ($gateway['ipprotocol'] == "inet6")) {
705
				if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgwv6")) {
706
					$gateway['defaultgw'] = true;
707
					$found_defaultv6 = 1;
708
				}
709
			}
710
		}
711
	}
712

    
713
	if($localhost === true) {
714
		/* attach localhost for Null routes */
715
		$gwlo4 = array();
716
		$gwlo4['name'] = "Null4";
717
		$gwlo4['interface'] = "lo0";
718
		$gwlo4['ipprotocol'] = "inet";
719
		$gwlo4['gateway'] = "127.0.0.1";
720
		$gwlo6 = array();
721
		$gwlo6['name'] = "Null6";
722
		$gwlo6['interface'] = "lo0";
723
		$gwlo6['ipprotocol'] = "inet6";
724
		$gwlo6['gateway'] = "::1";
725
		$gateways_arr['Null4'] = $gwlo4;
726
		$gateways_arr['Null6'] = $gwlo6;
727
	}
728
	return($gateways_arr);
729
}
730

    
731
function fixup_default_gateway($ipprotocol, $gateways_status, $gateways_arr) {
732
	global $config, $g;
733
	/*
734
	 * NOTE: The code below is meant to replace the default gateway when it goes down.
735
	 *	This facilitates services running on pfSense itself and are not handled by a PBR to continue working.
736
	 */
737
	$upgw = "";
738
	$dfltgwdown = false;
739
	$dfltgwfound = false;
740
	foreach ($gateways_arr as $gwname => $gwsttng) {
741
		if (($gwsttng['ipprotocol'] == $ipprotocol) && isset($gwsttng['defaultgw'])) {
742
			$dfltgwfound = true;
743
			$dfltgwname = $gwname;
744
			if (!isset($gwsttng['monitor_disable']) && stristr($gateways_status[$gwname]['status'], "down"))
745
				$dfltgwdown = true;
746
		}
747
		/* Keep a record of the last up gateway */
748
		/* XXX: Blacklist lan for now since it might cause issues to those who have a gateway set for it */
749
		if (empty($upgw) && ($gwsttng['ipprotocol'] == $ipprotocol) && (isset($gwsttng['monitor_disable']) || !stristr($gateways_status[$gwname]['status'], "down")) && $gwsttng[$gwname]['friendlyiface'] != "lan")
750
			$upgw = $gwname;
751
		if ($dfltgwdown == true && !empty($upgw))
752
			break;
753
	}
754
	if ($dfltgwfound == false) {
755
		$gwname = convert_friendly_interface_to_friendly_descr("wan");
756
		if (!empty($gateways_status[$gwname]) && stristr($gateways_status[$gwname]['status'], "down"))
757
			$dfltgwdown = true;
758
	}
759
	if ($dfltgwdown == true && !empty($upgw)) {
760
		if ($gateways_arr[$upgw]['gateway'] == "dynamic")
761
			$gateways_arr[$upgw]['gateway'] = get_interface_gateway($gateways_arr[$upgw]['friendlyiface']);
762
		if (is_ipaddr($gateways_arr[$upgw]['gateway'])) {
763
			log_error("Default gateway down setting {$upgw} as default!");
764
			if(is_ipaddrv6($gateways_arr[$upgw]['gateway'])) {
765
				$inetfamily = "-inet6";
766
			} else {
767
				$inetfamily = "-inet";
768
			}
769
			mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$upgw]['gateway']}");
770
		}
771
	} else {
772
		$defaultgw = trim(exec("/sbin/route -n get -{$ipprotocol} default | /usr/bin/awk '/gateway:/ {print $2}'"), " \n");
773
		if(is_ipaddrv6($gateways_arr[$dfltgwname]['gateway'])) {
774
			$inetfamily = "-inet6";
775
		} else {
776
			$inetfamily = "-inet";
777
		}
778
		if ($defaultgw != $gateways_arr[$dfltgwname]['gateway'])
779
			mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$dfltgwname]['gateway']}");
780
	}
781
}
782

    
783
/*
784
 * Return an array with all gateway groups with name as key
785
 * All gateway groups will be processed before returning the array.
786
 */
787
function return_gateway_groups_array() {
788
	global $config, $g;
789

    
790
	/* fetch the current gateways status */
791
	$gateways_status = return_gateways_status(true);
792
	$gateways_arr = return_gateways_array();
793
	$gateway_groups_array = array();
794

    
795
	if (isset($config['system']['gw_switch_default'])) {
796
		fixup_default_gateway("inet", $gateways_status, $gateways_arr);
797
		fixup_default_gateway("inet6", $gateways_status, $gateways_arr);
798
	}
799
	if (is_array($config['gateways']['gateway_group'])) {
800
		$carplist = get_configured_carp_interface_list();
801
		foreach ($config['gateways']['gateway_group'] as $group) {
802
			/* create array with group gateways members separated by tier */
803
			$tiers = array();
804
			$backupplan = array();
805
			$gwvip_arr = array();
806
			foreach ($group['item'] as $item) {
807
				list($gwname, $tier, $vipname) = explode("|", $item);
808

    
809
				if (is_ipaddr($carplist[$vipname])) {
810
					if (!is_array($gwvip_arr[$group['name']]))
811
						$gwvip_arr[$group['name']] = array();
812
					$gwvip_arr[$group['name']][$gwname] = $vipname;
813
				}
814

    
815
				/* Do it here rather than reiterating again the group in case no member is up. */
816
				if (!is_array($backupplan[$tier]))
817
					$backupplan[$tier] = array();
818
				$backupplan[$tier][] = $gwname;
819

    
820
				/* check if the gateway is available before adding it to the array */
821
				if (is_array($gateways_status[$gwname])) {
822
					$status = $gateways_status[$gwname];
823
					$gwdown = false;
824
					if (stristr($status['status'], "down")) {
825
						$msg = sprintf(gettext("MONITOR: %s is down, omitting from routing group {$group['name']}"), $gwname);
826
						$gwdown = true;
827
					} else if (stristr($status['status'], "loss") && strstr($group['trigger'], "loss")) {
828
						/* packet loss */
829
						$msg = sprintf(gettext("MONITOR: %s has packet loss, omitting from routing group {$group['name']}"), $gwname);
830
						$gwdown = true;
831
					} else if (stristr($status['status'], "delay") && strstr($group['trigger'] , "latency")) {
832
						/* high latency */
833
						$msg = sprintf(gettext("MONITOR: %s has high latency, omitting from routing group {$group['name']}"), $gwname);
834
						$gwdown = true;
835
					}
836
					if ($gwdown == true) {
837
						log_error($msg);
838
						notify_via_growl($msg);
839
						notify_via_smtp($msg);
840
					} else {
841
						/* Online add member */
842
						if (!is_array($tiers[$tier]))
843
							$tiers[$tier] = array();
844
						$tiers[$tier][] = $gwname;
845
					}
846
				} else if (isset($gateways_arr[$gwname]['monitor_disable']))
847
					$tiers[$tier][] = $gwname;
848
			}
849
			$tiers_count = count($tiers);
850
			if ($tiers_count == 0) {
851
				/* Oh dear, we have no members! Engage Plan B */
852
				if (!$g['booting']) {
853
					$msg = gettext("Gateways status could not be determined, considering all as up/active. (Group: {$group['name']})");
854
					log_error($msg);
855
					notify_via_growl($msg);
856
					//notify_via_smtp($msg);
857
				}
858
				$tiers = $backupplan;
859
			}
860
			/* sort the tiers array by the tier key */
861
			ksort($tiers);
862

    
863
			/* we do not really foreach the tiers as we stop after the first tier */
864
			foreach ($tiers as $tieridx => $tier) {
865
				/* process all gateways in this tier */
866
				foreach ($tier as $member) {
867
					/* determine interface gateway */
868
					if (isset($gateways_arr[$member])) {
869
						$gateway = $gateways_arr[$member];
870
						$int = $gateway['interface'];
871
						$gatewayip = "";
872
						if(is_ipaddr($gateway['gateway']))
873
							$gatewayip = $gateway['gateway'];
874
						else if (!empty($int))
875
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
876

    
877
						if (!empty($int)) {
878
							$gateway_groups_array[$group['name']]['ipprotocol'] = $gateway['ipprotocol'];
879
							if (is_ipaddr($gatewayip)) {
880
								$groupmember = array();
881
								$groupmember['int']  = $int;
882
								$groupmember['gwip']  = $gatewayip;
883
								$groupmember['weight']  = isset($gateway['weight']) ? $gateway['weight'] : 1;
884
								if (is_array($gwvip_arr[$group['name']])&& !empty($gwvip_arr[$group['name']][$member]))
885
									$groupmember['vip'] = $gwvip_arr[$group['name']][$member];
886
								$gateway_groups_array[$group['name']][] = $groupmember;
887
							}
888
						}
889
					}
890
				}
891
				/* we should have the 1st available tier now, exit stage left */
892
				if (count($gateway_groups_array[$group['name']]) > 0)
893
					break;
894
				else
895
					log_error("GATEWAYS: Group {$group['name']} did not have any gateways up on tier {$tieridx}!");
896
			}
897
		}
898
	}
899

    
900
	return ($gateway_groups_array);
901
}
902

    
903
/* Update DHCP WAN Interface ip address in gateway group item */
904
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
905
	global $config, $g;
906
	foreach($config['gateways']['gateway_item'] as & $gw) {
907
		if($gw['interface'] == $interface) {
908
			$current_gw = get_interface_gateway($interface);
909
			if($gw['gateway'] <> $current_gw) {
910
				$gw['gateway'] = $current_gw;
911
				$changed = true;
912
			}
913
		}
914
	}
915
	if($changed && $current_gw)
916
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interfac, $current_gw));
917
}
918

    
919
function lookup_gateway_ip_by_name($name) {
920

    
921
	$gateways_arr = return_gateways_array(false, true);
922
	foreach ($gateways_arr as $gname => $gw) {
923
		if ($gw['name'] === $name || $gname === $name)
924
			return $gw['gateway'];
925
	}
926

    
927
	return false;
928
}
929

    
930
function lookup_gateway_monitor_ip_by_name($name) {
931

    
932
	$gateways_arr = return_gateways_array(false, true);
933
	if (!empty($gateways_arr[$name])) {
934
		$gateway = $gateways_arr[$name];
935
		if(!is_ipaddr($gateway['monitor']))
936
			return $gateway['gateway'];
937

    
938
		return $gateway['monitor'];
939
	}
940

    
941
	return (false);
942
}
943

    
944
function lookup_gateway_interface_by_name($name) {
945

    
946
	$gateways_arr = return_gateways_array(false, true);
947
	if (!empty($gateways_arr[$name])) {
948
		$interfacegw = $gateways_arr[$name]['friendlyiface'];
949
		return ($interfacegw);
950
	}
951

    
952
	return (false);
953
}
954

    
955
function get_interface_gateway($interface, &$dynamic = false) {
956
	global $config, $g;
957

    
958
	$gw = NULL;
959

    
960
	$gwcfg = $config['interfaces'][$interface];
961
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
962
		foreach($config['gateways']['gateway_item'] as $gateway) {
963
			if(($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
964
				$gw = $gateway['gateway'];
965
				break;
966
			}
967
		}
968
	}
969

    
970
	// for dynamic interfaces we handle them through the $interface_router file.
971
	if (!is_ipaddrv4($gw) && !is_ipaddrv4($gwcfg['ipaddr'])) {
972
		$realif = get_real_interface($interface);
973
		if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
974
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
975
			$dynamic = true;
976
		}
977
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw"))
978
			$dynamic = "default";
979

    
980
	}
981

    
982
	/* return gateway */
983
	return ($gw);
984
}
985

    
986
function get_interface_gateway_v6($interface, &$dynamic = false) {
987
	global $config, $g;
988

    
989
	$gw = NULL;
990
	$gwcfg = $config['interfaces'][$interface];
991
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
992
		foreach($config['gateways']['gateway_item'] as $gateway) {
993
			if(($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
994
				$gw = $gateway['gateway'];
995
				break;
996
			}
997
		}
998
	}
999

    
1000
	// for dynamic interfaces we handle them through the $interface_router file.
1001
	if (!is_ipaddrv6($gw) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
1002
			$realif = get_real_interface($interface);
1003
			if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
1004
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
1005
				$dynamic = true;
1006
			}
1007
			if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6"))
1008
				$dynamic = "default";
1009

    
1010
	}
1011
	/* return gateway */
1012
	return ($gw);
1013
}
1014

    
1015
/* Check a IP address against a gateway IP or name
1016
 * to verify it's address family */
1017
function validate_address_family($ipaddr, $gwname) {
1018
	$v4ip = false;
1019
	$v6ip = false;
1020
	$v4gw = false;
1021
	$v6gw = false;
1022

    
1023
	if(is_ipaddrv4($ipaddr))
1024
		$v4ip = true;
1025
	if(is_ipaddrv6($ipaddr))
1026
		$v6ip = true;
1027
	if(is_ipaddrv4($gwname))
1028
		$v4gw = true;
1029
	if(is_ipaddrv6($gwname))
1030
		$v6gw = true;
1031

    
1032
	if($v4ip && $v4gw)
1033
		return true;
1034
	if($v6ip && $v6gw)
1035
		return true;
1036

    
1037
	/* still no match, carry on, lookup gateways */
1038
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
1039
		$v4gw = true;
1040
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
1041
		$v6gw = true;
1042

    
1043
	$gw_array = return_gateways_array();
1044
	if(is_array($gw_array[$gwname])) {
1045
		switch($gw_array[$gwname]['ipprotocol']) {
1046
			case "inet":
1047
				$v4gw = true;
1048
				break;
1049
			case "inet6":
1050
				$v6gw = true;
1051
				break;
1052
		}
1053
	}
1054

    
1055
	if($v4ip && $v4gw)
1056
		return true;
1057
	if($v6ip && $v6gw)
1058
		return true;
1059

    
1060
	return false;
1061
}
1062

    
1063
/* check if a interface is part of a gateway group */
1064
function interface_gateway_group_member($interface) {
1065
	global $config;
1066

    
1067
	if (is_array($config['gateways']['gateway_group']))
1068
		$groups = $config['gateways']['gateway_group'];
1069
	else
1070
		return false;
1071

    
1072
	$gateways_arr = return_gateways_array(false, true);
1073
	foreach($groups as $group) {
1074
		if(is_array($group['item'])) {
1075
			foreach($group['item'] as $item) {
1076
				$elements = explode("|", $item);
1077
				$gwname = $elements[0];
1078
				if ($interface == $gateways_arr[$gwname]['interface']) {
1079
					unset($gateways_arr);
1080
					return true;
1081
				}
1082
			}
1083
		}
1084
	}
1085
	unset($gateways_arr);
1086

    
1087
	return false;
1088
}
1089

    
1090
function gateway_is_gwgroup_member($name) {
1091
	global $config;
1092

    
1093
	if (is_array($config['gateways']['gateway_group']))
1094
		$groups = $config['gateways']['gateway_group'];
1095
	else
1096
		return false;
1097

    
1098
	$members = array();
1099
	foreach($groups as $group) {
1100
		if (is_array($group['item'])) {
1101
			foreach($group['item'] as $item) {
1102
				$elements = explode("|", $item);
1103
				$gwname = $elements[0];
1104
				if ($name == $elements[0])
1105
					$members[] = $group['name'];
1106
			}
1107
		}
1108
	}
1109

    
1110
	return $members;
1111
}
1112
?>
(25-25/68)