Projet

Général

Profil

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

univnautes / etc / inc / gwlb.inc @ 8ff231b4

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_default = return_apinger_defaults();
65
	$apingerconfig = <<<EOD
66

    
67
# pfSense apinger configuration file. Automatically Generated!
68

    
69
## User and group the pinger should run as
70
user "root"
71
group "wheel"
72

    
73
## Mailer to use (default: "/usr/lib/sendmail -t")
74
#mailer "/var/qmail/bin/qmail-inject"
75

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

    
79
## Format of timestamp (%s macro) (default: "%b %d %H:%M:%S")
80
#timestamp_format "%Y%m%d%H%M%S"
81

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

    
90
########################################
91
# RRDTool status gathering configuration
92
# Interval between RRD updates
93
rrd interval 60s;
94

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

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

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

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

    
124
target default {
125
	## How often the probe should be sent
126
	interval {$apinger_default['interval']}s
127

    
128
	## How many replies should be used to compute average delay
129
	## for controlling "delay" alarms
130
	avg_delay_samples {$apinger_default['avg_delay_samples']}
131

    
132
	## How many probes should be used to compute average loss
133
	avg_loss_samples {$apinger_default['avg_loss_samples']}
134

    
135
	## The delay (in samples) after which loss is computed
136
	## without this delays larger than interval would be treated as loss
137
	avg_loss_delay_samples {$apinger_default['avg_loss_delay_samples']}
138

    
139
	## Names of the alarms that may be generated for the target
140
	alarms "down","delay","loss"
141

    
142
	## Location of the RRD
143
	#rrd file "{$g['vardb_path']}/rrd/apinger-%t.rrd"
144
}
145

    
146
EOD;
147

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

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

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

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

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

    
229
		$monitor_ips[] = $gateway['monitor'];
230
		$apingercfg = "target \"{$gateway['monitor']}\" {\n";
231
		$apingercfg .= "	description \"{$name}\"\n";
232
		$apingercfg .= "	srcip \"{$gwifip}\"\n";
233

    
234
		## How often the probe should be sent
235
		if (!empty($gateway['interval']) &&  is_numeric($gateway['interval'])) {
236
			$interval = intval($gateway['interval']);	# Restrict to Integer
237
			if ($interval <  1) $interval =  1;	# Minimum
238
			if ($interval != $apinger_default['interval'])	# If not default value
239
				$apingercfg .= "	interval " . $interval . "s\n";
240
		}
241

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

    
251
		## How many probes should be used to compute average loss
252
		if (!empty($gateway['avg_loss_samples']) && is_numeric($gateway['avg_loss_samples'])) {
253
			$avg_loss_samples = intval($gateway['avg_loss_samples']);	# Restrict to Integer
254
			if ($avg_loss_samples < 1) $avg_loss_samples = 1;	# Minimum
255
			if ($avg_loss_samples != $apinger_default['avg_loss_samples'])	# If not default value
256
				$apingercfg .= "	avg_loss_samples " . $avg_loss_samples . "\n";
257
		}
258

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

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

    
316
		if (isset($gateway['force_down']))
317
			$apingercfg .= "\tforce_down on\n";
318

    
319
		$apingercfg .= "	rrd file \"{$g['vardb_path']}/rrd/{$gateway['name']}-quality.rrd\"\n";
320
		$apingercfg .= "}\n";
321
		$apingercfg .= "\n";
322

    
323
		$apingerconfig .= $alarmscfg;
324
		$apingerconfig .= $apingercfg;
325

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

    
334
	if (is_dir("{$g['tmp_path']}"))
335
		chmod("{$g['tmp_path']}", 01777);
336
	if (!is_dir("{$g['vardb_path']}/rrd"))
337
		mkdir("{$g['vardb_path']}/rrd", 0775);
338

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

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

    
353
	return 0;
354
}
355

    
356
/* return the status of the apinger targets as a array */
357
function return_gateways_status($byname = false) {
358
	global $config, $g;
359

    
360
	$apingerstatus = array();
361
	/* Always get the latest status from apinger */
362
	if (file_exists("{$g['varrun_path']}/apinger.pid"))
363
                sigkillbypid("{$g['varrun_path']}/apinger.pid", "USR1");
364
	if (file_exists("{$g['varrun_path']}/apinger.status")) {
365
		$apingerstatus = file("{$g['varrun_path']}/apinger.status");
366
	} else
367
		$apingerstatus = array();
368

    
369
	$status = array();
370
	foreach($apingerstatus as $line) {
371
		$info = explode("|", $line);
372
		if ($byname == false)
373
			$target = $info[0];
374
		else
375
			$target = $info[2];
376

    
377
		$status[$target] = array();
378
		$status[$target]['monitorip'] = $info[0];
379
		$status[$target]['srcip'] = $info[1];
380
		$status[$target]['name'] = $info[2];
381
		$status[$target]['lastcheck'] = $info[5] ? date('r', $info[5]) : date('r');
382
		$status[$target]['delay'] = empty($info[6]) ? "0ms" : round($info[6], 1) ."ms" ;
383
		$status[$target]['loss'] = empty($info[7]) ? "0.0%" : round($info[7], 1) . "%";
384
		$status[$target]['status'] = trim($info[8]);
385
	}
386

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

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

    
429
/* Return all configured gateways on the system */
430
function return_gateways_array($disabled = false, $localhost = false, $inactive = false) {
431
	global $config, $g;
432

    
433
	$gateways_arr = array();
434

    
435
	$found_defaultv4 = 0;
436
	$found_defaultv6 = 0;
437

    
438
	// Ensure the interface cache is up to date first
439
	$interfaces = get_interface_arr(true);
440
	$interfaces_v4 = array();
441
	$interfaces_v6 = array();
442

    
443
	$i = -1;
444
	/* Process/add all the configured gateways. */
445
	if (is_array($config['gateways']['gateway_item'])) {
446
		foreach ($config['gateways']['gateway_item'] as $gateway) {
447
			/* Increment it here to do not skip items */
448
			$i++;
449

    
450
			if (empty($config['interfaces'][$gateway['interface']])) {
451
				if ($inactive === false)
452
					continue;
453
				else
454
					$gateway['inactive'] = true;
455
			}
456
			$wancfg = $config['interfaces'][$gateway['interface']];
457

    
458
			/* skip disabled interfaces */
459
			if ($disabled === false && (!isset($wancfg['enable']) || isset($gateway['disabled'])))
460
				continue;
461

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

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

    
491
			if (isset($gateway['monitor_disable']))
492
				$gateway['monitor_disable'] = true;
493
			else if (empty($gateway['monitor']))
494
				$gateway['monitor'] = $gateway['gateway'];
495

    
496
			$gateway['friendlyiface'] = $gateway['interface'];
497

    
498
			/* special treatment for tunnel interfaces */
499
			if ($gateway['ipprotocol'] == "inet6") {
500
				$gateway['interface'] = get_real_interface($gateway['interface'], "inet6", false, false);
501
				$interfaces_v6[$gateway['friendlyiface']] = $gateway['friendlyiface'];
502
			} else {
503
				$gateway['interface'] = get_real_interface($gateway['interface'], "all", false, false);
504
				$interfaces_v4[$gateway['friendlyiface']] = $gateway['friendlyiface'];
505
			}
506

    
507
			/* entry has a default flag, use it */
508
			if (isset($gateway['defaultgw'])) {
509
				if ($gateway['ipprotocol'] == "inet") {
510
					$gateway['defaultgw'] = true;
511
					$found_defaultv4 = 1;
512
				} else if ($gateway['ipprotocol'] == "inet6") {
513
					$gateway['defaultgw'] = true;
514
					$found_defaultv6 = 1;
515
				}
516
			}
517
			/* include the gateway index as the attribute */
518
			$gateway['attribute'] = $i;
519

    
520
			$gateways_arr[$gateway['name']] = $gateway;
521
		}
522
	}
523
	unset($gateway);
524

    
525
	/* Loop through all interfaces with a gateway and add it to a array */
526
	if ($disabled == false)
527
		$iflist = get_configured_interface_with_descr();
528
	else
529
		$iflist = get_configured_interface_with_descr(false, true);
530

    
531
	/* Process/add dynamic v4 gateways. */
532
	foreach($iflist as $ifname => $friendly ) {
533
		if(! interface_has_gateway($ifname))
534
			continue;
535

    
536
		if (empty($config['interfaces'][$ifname]))
537
			continue;
538

    
539
		$ifcfg = &$config['interfaces'][$ifname];
540
		if(!isset($ifcfg['enable']))
541
			continue;
542

    
543
		if(!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr']))
544
			continue;
545

    
546
		if (isset($interfaces_v4[$ifname]))
547
			continue;
548

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

    
563
					$ctype = "VPNv4";
564
				}
565
				break;
566
		}
567
		$ctype = "_". strtoupper($ctype);
568

    
569
		$gateway = array();
570
		$gateway['dynamic'] = false;
571
		$gateway['ipprotocol'] = "inet";
572
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
573
		$gateway['interface'] = get_real_interface($ifname);
574
		$gateway['friendlyiface'] = $ifname;
575
		$gateway['name'] = "{$friendly}{$ctype}";
576
		$gateway['attribute'] = "system";
577

    
578
		if (($gateway['dynamic'] === "default") && ($found_defaultv4 == 0)) {
579
			$gateway['defaultgw'] = true;
580
			$gateway['dynamic'] = true;
581
			$found_defaultv4 = 1;
582
		}
583
		/* Loopback dummy for dynamic interfaces without a IP */
584
		if (!is_ipaddrv4($gateway['gateway']) && $gateway['dynamic'] == true)
585
			$gateway['gateway'] = "dynamic";
586

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

    
594
		if (is_ipaddrv4($gateway['gateway']))
595
			$gateway['monitor'] = $gateway['gateway'];
596

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

    
602
	/* Process/add dynamic v6 gateways. */
603
	foreach($iflist as $ifname => $friendly ) {
604
		/* If the user has disabled IPv6, they probably don't want any IPv6 gateways. */
605
		if (!isset($config['system']['ipv6allow']))
606
			break;
607

    
608
		if(! interface_has_gatewayv6($ifname))
609
			continue;
610

    
611
		if (empty($config['interfaces'][$ifname]))
612
			continue;
613

    
614
		$ifcfg = &$config['interfaces'][$ifname];
615
		if(!isset($ifcfg['enable']))
616
			continue;
617

    
618
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
619
			continue;
620

    
621
		if(isset($interfaces_v6[$ifname]))
622
			continue;
623

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

    
639
					$ctype = "VPNv6";
640
				} else if ($tunnelif == "gif" || $tunnelif == "gre")
641
					$ctype = "TUNNELv6";
642
				break;
643
		}
644
		$ctype = "_". strtoupper($ctype);
645

    
646
		$gateway = array();
647
		$gateway['dynamic'] = false;
648
		$gateway['ipprotocol'] = "inet6";
649
		$gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
650
		$gateway['interface'] = get_real_interface($ifname, "inet6");
651
		switch($ifcfg['ipaddrv6']) {
652
			case "6rd":
653
			case "6to4":
654
				$gateway['dynamic'] = "default";
655
				break;
656
		}
657
		$gateway['friendlyiface'] = $ifname;
658
		$gateway['name'] = "{$friendly}{$ctype}";
659
		$gateway['attribute'] = "system";
660

    
661
		if (($gateway['dynamic'] === "default")  && ($found_defaultv6 == 0)) {
662
			$gateway['defaultgw'] = true;
663
			$gateway['dynamic'] = true;
664
			$found_defaultv6 = 1;
665
		}
666

    
667
		/* Loopback dummy for dynamic interfaces without a IP */
668
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
669
			$gateway['gateway'] = "dynamic";
670

    
671
		/* automatically skip known static and dynamic gateways we have a array entry for */
672
		foreach($gateways_arr as $gateway_item) {
673
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
674
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
675
					continue 2;
676
		}
677

    
678
		if (is_ipaddrv6($gateway['gateway']))
679
			$gateway['monitor'] = $gateway['gateway'];
680

    
681
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
682
		$gateways_arr[$gateway['name']] = $gateway;
683
	}
684
	unset($gateway);
685

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

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

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

    
777
/*
778
 * Return an array with all gateway groups with name as key
779
 * All gateway groups will be processed before returning the array.
780
 */
781
function return_gateway_groups_array() {
782
	global $config, $g;
783

    
784
	/* fetch the current gateways status */
785
	$gateways_status = return_gateways_status(true);
786
	$gateways_arr = return_gateways_array();
787
	$gateway_groups_array = array();
788

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

    
803
				if (is_ipaddr($carplist[$vipname])) {
804
					if (!is_array($gwvip_arr[$group['name']]))
805
						$gwvip_arr[$group['name']] = array();
806
					$gwvip_arr[$group['name']][$gwname] = $vipname;
807
				}
808

    
809
				/* Do it here rather than reiterating again the group in case no member is up. */
810
				if (!is_array($backupplan[$tier]))
811
					$backupplan[$tier] = array();
812
				$backupplan[$tier][] = $gwname;
813

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

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

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

    
894
	return ($gateway_groups_array);
895
}
896

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

    
913
function lookup_gateway_ip_by_name($name) {
914

    
915
	$gateways_arr = return_gateways_array(false, true);
916
	foreach ($gateways_arr as $gname => $gw) {
917
		if ($gw['name'] === $name || $gname === $name)
918
			return $gw['gateway'];
919
	}
920

    
921
	return false;
922
}
923

    
924
function lookup_gateway_monitor_ip_by_name($name) {
925

    
926
	$gateways_arr = return_gateways_array(false, true);
927
	if (!empty($gateways_arr[$name])) {
928
		$gateway = $gateways_arr[$name];
929
		if(!is_ipaddr($gateway['monitor']))
930
			return $gateway['gateway'];
931

    
932
		return $gateway['monitor'];
933
	}
934

    
935
	return (false);
936
}
937

    
938
function lookup_gateway_interface_by_name($name) {
939

    
940
	$gateways_arr = return_gateways_array(false, true);
941
	if (!empty($gateways_arr[$name])) {
942
		$interfacegw = $gateways_arr[$name]['friendlyiface'];
943
		return ($interfacegw);
944
	}
945

    
946
	return (false);
947
}
948

    
949
function get_interface_gateway($interface, &$dynamic = false) {
950
	global $config, $g;
951

    
952
	$gw = NULL;
953

    
954
	$gwcfg = $config['interfaces'][$interface];
955
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
956
		foreach($config['gateways']['gateway_item'] as $gateway) {
957
			if(($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
958
				$gw = $gateway['gateway'];
959
				break;
960
			}
961
		}
962
	}
963

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

    
974
	}
975

    
976
	/* return gateway */
977
	return ($gw);
978
}
979

    
980
function get_interface_gateway_v6($interface, &$dynamic = false) {
981
	global $config, $g;
982

    
983
	$gw = NULL;
984
	$gwcfg = $config['interfaces'][$interface];
985
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
986
		foreach($config['gateways']['gateway_item'] as $gateway) {
987
			if(($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
988
				$gw = $gateway['gateway'];
989
				break;
990
			}
991
		}
992
	}
993

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

    
1004
	}
1005
	/* return gateway */
1006
	return ($gw);
1007
}
1008

    
1009
/* Check a IP address against a gateway IP or name
1010
 * to verify it's address family */
1011
function validate_address_family($ipaddr, $gwname) {
1012
	$v4ip = false;
1013
	$v6ip = false;
1014
	$v4gw = false;
1015
	$v6gw = false;
1016

    
1017
	if(is_ipaddrv4($ipaddr))
1018
		$v4ip = true;
1019
	if(is_ipaddrv6($ipaddr))
1020
		$v6ip = true;
1021
	if(is_ipaddrv4($gwname))
1022
		$v4gw = true;
1023
	if(is_ipaddrv6($gwname))
1024
		$v6gw = true;
1025

    
1026
	if($v4ip && $v4gw)
1027
		return true;
1028
	if($v6ip && $v6gw)
1029
		return true;
1030

    
1031
	/* still no match, carry on, lookup gateways */
1032
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
1033
		$v4gw = true;
1034
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
1035
		$v6gw = true;
1036

    
1037
	$gw_array = return_gateways_array();
1038
	if(is_array($gw_array[$gwname])) {
1039
		switch($gw_array[$gwname]['ipprotocol']) {
1040
			case "inet":
1041
				$v4gw = true;
1042
				break;
1043
			case "inet6":
1044
				$v6gw = true;
1045
				break;
1046
		}
1047
	}
1048

    
1049
	if($v4ip && $v4gw)
1050
		return true;
1051
	if($v6ip && $v6gw)
1052
		return true;
1053

    
1054
	return false;
1055
}
1056

    
1057
/* check if a interface is part of a gateway group */
1058
function interface_gateway_group_member($interface) {
1059
	global $config;
1060

    
1061
	if (is_array($config['gateways']['gateway_group']))
1062
		$groups = $config['gateways']['gateway_group'];
1063
	else
1064
		return false;
1065

    
1066
	$gateways_arr = return_gateways_array(false, true);
1067
	foreach($groups as $group) {
1068
		if(is_array($group['item'])) {
1069
			foreach($group['item'] as $item) {
1070
				$elements = explode("|", $item);
1071
				$gwname = $elements[0];
1072
				if ($interface == $gateways_arr[$gwname]['interface']) {
1073
					unset($gateways_arr);
1074
					return true;
1075
				}
1076
			}
1077
		}
1078
	}
1079
	unset($gateways_arr);
1080

    
1081
	return false;
1082
}
1083

    
1084
function gateway_is_gwgroup_member($name) {
1085
	global $config;
1086

    
1087
	if (is_array($config['gateways']['gateway_group']))
1088
		$groups = $config['gateways']['gateway_group'];
1089
	else
1090
		return false;
1091

    
1092
	$members = array();
1093
	foreach($groups as $group) {
1094
		if (is_array($group['item'])) {
1095
			foreach($group['item'] as $item) {
1096
				$elements = explode("|", $item);
1097
				$gwname = $elements[0];
1098
				if ($name == $elements[0])
1099
					$members[] = $group['name'];
1100
			}
1101
		}
1102
	}
1103

    
1104
	return $members;
1105
}
1106
?>
(25-25/68)