Projet

Général

Profil

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

univnautes / etc / inc / gwlb.inc @ 96fcabaa

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
					$ctype = "VPNv4";
560
				break;
561
		}
562
		$ctype = "_". strtoupper($ctype);
563

    
564
		$gateway = array();
565
		$gateway['dynamic'] = false;
566
		$gateway['ipprotocol'] = "inet";
567
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
568
		$gateway['interface'] = get_real_interface($ifname);
569
		$gateway['friendlyiface'] = $ifname;
570
		$gateway['name'] = "{$friendly}{$ctype}";
571
		$gateway['attribute'] = "system";
572

    
573
		if (($gateway['dynamic'] === "default") && ($found_defaultv4 == 0)) {
574
			$gateway['defaultgw'] = true;
575
			$gateway['dynamic'] = true;
576
			$found_defaultv4 = 1;
577
		}
578
		/* Loopback dummy for dynamic interfaces without a IP */
579
		if (!is_ipaddrv4($gateway['gateway']) && $gateway['dynamic'] == true)
580
			$gateway['gateway'] = "dynamic";
581

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

    
589
		if (is_ipaddrv4($gateway['gateway']))
590
			$gateway['monitor'] = $gateway['gateway'];
591

    
592
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
593
		$gateways_arr[$gateway['name']] = $gateway;
594
	}
595
	unset($gateway);
596

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

    
603
		if(! interface_has_gatewayv6($ifname))
604
			continue;
605

    
606
		if (empty($config['interfaces'][$ifname]))
607
			continue;
608

    
609
		$ifcfg = &$config['interfaces'][$ifname];
610
		if(!isset($ifcfg['enable']))
611
			continue;
612

    
613
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
614
			continue;
615

    
616
		if(isset($interfaces_v6[$ifname]))
617
			continue;
618

    
619
		$ctype = "";
620
		switch($ifcfg['ipaddrv6']) {
621
			case "slaac":
622
			case "dhcp6":
623
			case "6to4":
624
			case "6rd":
625
				$ctype = strtoupper($ifcfg['ipaddrv6']);
626
				break;
627
			default:
628
				$tunnelif = substr($ifcfg['if'], 0, 3);
629
				if (substr($ifcfg['if'], 0, 4) ==  "ovpn")
630
					$ctype = "VPNv6";
631
				else if ($tunnelif == "gif" || $tunnelif == "gre")
632
					$ctype = "TUNNELv6";
633
				break;
634
		}
635
		$ctype = "_". strtoupper($ctype);
636

    
637
		$gateway = array();
638
		$gateway['dynamic'] = false;
639
		$gateway['ipprotocol'] = "inet6";
640
		$gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
641
		$gateway['interface'] = get_real_interface($ifname, "inet6");
642
		switch($ifcfg['ipaddrv6']) {
643
			case "6rd":
644
			case "6to4":
645
				$gateway['dynamic'] = "default";
646
				break;
647
		}
648
		$gateway['friendlyiface'] = $ifname;
649
		$gateway['name'] = "{$friendly}{$ctype}";
650
		$gateway['attribute'] = "system";
651

    
652
		if (($gateway['dynamic'] === "default")  && ($found_defaultv6 == 0)) {
653
			$gateway['defaultgw'] = true;
654
			$gateway['dynamic'] = true;
655
			$found_defaultv6 = 1;
656
		}
657

    
658
		/* Loopback dummy for dynamic interfaces without a IP */
659
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
660
			$gateway['gateway'] = "dynamic";
661

    
662
		/* automatically skip known static and dynamic gateways we have a array entry for */
663
		foreach($gateways_arr as $gateway_item) {
664
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
665
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
666
					continue 2;
667
		}
668

    
669
		if (is_ipaddrv6($gateway['gateway']))
670
			$gateway['monitor'] = $gateway['gateway'];
671

    
672
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
673
		$gateways_arr[$gateway['name']] = $gateway;
674
	}
675
	unset($gateway);
676

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

    
698
	if($localhost === true) {
699
		/* attach localhost for Null routes */
700
		$gwlo4 = array();
701
		$gwlo4['name'] = "Null4";
702
		$gwlo4['interface'] = "lo0";
703
		$gwlo4['ipprotocol'] = "inet";
704
		$gwlo4['gateway'] = "127.0.0.1";
705
		$gwlo6 = array();
706
		$gwlo6['name'] = "Null6";
707
		$gwlo6['interface'] = "lo0";
708
		$gwlo6['ipprotocol'] = "inet6";
709
		$gwlo6['gateway'] = "::1";
710
		$gateways_arr['Null4'] = $gwlo4;
711
		$gateways_arr['Null6'] = $gwlo6;
712
	}
713
	return($gateways_arr);
714
}
715

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

    
768
/*
769
 * Return an array with all gateway groups with name as key
770
 * All gateway groups will be processed before returning the array.
771
 */
772
function return_gateway_groups_array() {
773
	global $config, $g;
774

    
775
	/* fetch the current gateways status */
776
	$gateways_status = return_gateways_status(true);
777
	$gateways_arr = return_gateways_array();
778
	$gateway_groups_array = array();
779

    
780
	if (isset($config['system']['gw_switch_default'])) {
781
		fixup_default_gateway("inet", $gateways_status, $gateways_arr);
782
		fixup_default_gateway("inet6", $gateways_status, $gateways_arr);
783
	}
784
	if (is_array($config['gateways']['gateway_group'])) {
785
		$carplist = get_configured_carp_interface_list();
786
		foreach ($config['gateways']['gateway_group'] as $group) {
787
			/* create array with group gateways members separated by tier */
788
			$tiers = array();
789
			$backupplan = array();
790
			$gwvip_arr = array();
791
			foreach ($group['item'] as $item) {
792
				list($gwname, $tier, $vipname) = explode("|", $item);
793

    
794
				if (is_ipaddr($carplist[$vipname])) {
795
					if (!is_array($gwvip_arr[$group['name']]))
796
						$gwvip_arr[$group['name']] = array();
797
					$gwvip_arr[$group['name']][$gwname] = $vipname;
798
				}
799

    
800
				/* Do it here rather than reiterating again the group in case no member is up. */
801
				if (!is_array($backupplan[$tier]))
802
					$backupplan[$tier] = array();
803
				$backupplan[$tier][] = $gwname;
804

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

    
848
			/* we do not really foreach the tiers as we stop after the first tier */
849
			foreach ($tiers as $tieridx => $tier) {
850
				/* process all gateways in this tier */
851
				foreach ($tier as $member) {
852
					/* determine interface gateway */
853
					if (isset($gateways_arr[$member])) {
854
						$gateway = $gateways_arr[$member];
855
						$int = $gateway['interface'];
856
						$gatewayip = "";
857
						if(is_ipaddr($gateway['gateway']))
858
							$gatewayip = $gateway['gateway'];
859
						else if (!empty($int))
860
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
861

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

    
885
	return ($gateway_groups_array);
886
}
887

    
888
/* Update DHCP WAN Interface ip address in gateway group item */
889
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
890
	global $config, $g;
891
	foreach($config['gateways']['gateway_item'] as & $gw) {
892
		if($gw['interface'] == $interface) {
893
			$current_gw = get_interface_gateway($interface);
894
			if($gw['gateway'] <> $current_gw) {
895
				$gw['gateway'] = $current_gw;
896
				$changed = true;
897
			}
898
		}
899
	}
900
	if($changed && $current_gw)
901
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interfac, $current_gw));
902
}
903

    
904
function lookup_gateway_ip_by_name($name) {
905

    
906
	$gateways_arr = return_gateways_array(false, true);
907
	foreach ($gateways_arr as $gname => $gw) {
908
		if ($gw['name'] === $name || $gname === $name)
909
			return $gw['gateway'];
910
	}
911

    
912
	return false;
913
}
914

    
915
function lookup_gateway_monitor_ip_by_name($name) {
916

    
917
	$gateways_arr = return_gateways_array(false, true);
918
	if (!empty($gateways_arr[$name])) {
919
		$gateway = $gateways_arr[$name];
920
		if(!is_ipaddr($gateway['monitor']))
921
			return $gateway['gateway'];
922

    
923
		return $gateway['monitor'];
924
	}
925

    
926
	return (false);
927
}
928

    
929
function lookup_gateway_interface_by_name($name) {
930

    
931
	$gateways_arr = return_gateways_array(false, true);
932
	if (!empty($gateways_arr[$name])) {
933
		$interfacegw = $gateways_arr[$name]['friendlyiface'];
934
		return ($interfacegw);
935
	}
936

    
937
	return (false);
938
}
939

    
940
function get_interface_gateway($interface, &$dynamic = false) {
941
	global $config, $g;
942

    
943
	$gw = NULL;
944

    
945
	$gwcfg = $config['interfaces'][$interface];
946
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
947
		foreach($config['gateways']['gateway_item'] as $gateway) {
948
			if(($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
949
				$gw = $gateway['gateway'];
950
				break;
951
			}
952
		}
953
	}
954

    
955
	// for dynamic interfaces we handle them through the $interface_router file.
956
	if (!is_ipaddrv4($gw) && !is_ipaddrv4($gwcfg['ipaddr'])) {
957
		$realif = get_real_interface($interface);
958
		if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
959
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
960
			$dynamic = true;
961
		}
962
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw"))
963
			$dynamic = "default";
964

    
965
	}
966

    
967
	/* return gateway */
968
	return ($gw);
969
}
970

    
971
function get_interface_gateway_v6($interface, &$dynamic = false) {
972
	global $config, $g;
973

    
974
	$gw = NULL;
975
	$gwcfg = $config['interfaces'][$interface];
976
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
977
		foreach($config['gateways']['gateway_item'] as $gateway) {
978
			if(($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
979
				$gw = $gateway['gateway'];
980
				break;
981
			}
982
		}
983
	}
984

    
985
	// for dynamic interfaces we handle them through the $interface_router file.
986
	if (!is_ipaddrv6($gw) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
987
			$realif = get_real_interface($interface);
988
			if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
989
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
990
				$dynamic = true;
991
			}
992
			if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6"))
993
				$dynamic = "default";
994

    
995
	}
996
	/* return gateway */
997
	return ($gw);
998
}
999

    
1000
/* Check a IP address against a gateway IP or name
1001
 * to verify it's address family */
1002
function validate_address_family($ipaddr, $gwname) {
1003
	$v4ip = false;
1004
	$v6ip = false;
1005
	$v4gw = false;
1006
	$v6gw = false;
1007

    
1008
	if(is_ipaddrv4($ipaddr))
1009
		$v4ip = true;
1010
	if(is_ipaddrv6($ipaddr))
1011
		$v6ip = true;
1012
	if(is_ipaddrv4($gwname))
1013
		$v4gw = true;
1014
	if(is_ipaddrv6($gwname))
1015
		$v6gw = true;
1016

    
1017
	if($v4ip && $v4gw)
1018
		return true;
1019
	if($v6ip && $v6gw)
1020
		return true;
1021

    
1022
	/* still no match, carry on, lookup gateways */
1023
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
1024
		$v4gw = true;
1025
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
1026
		$v6gw = true;
1027

    
1028
	$gw_array = return_gateways_array();
1029
	if(is_array($gw_array[$gwname])) {
1030
		switch($gw_array[$gwname]['ipprotocol']) {
1031
			case "inet":
1032
				$v4gw = true;
1033
				break;
1034
			case "inet6":
1035
				$v6gw = true;
1036
				break;
1037
		}
1038
	}
1039

    
1040
	if($v4ip && $v4gw)
1041
		return true;
1042
	if($v6ip && $v6gw)
1043
		return true;
1044

    
1045
	return false;
1046
}
1047

    
1048
/* check if a interface is part of a gateway group */
1049
function interface_gateway_group_member($interface) {
1050
	global $config;
1051

    
1052
	if (is_array($config['gateways']['gateway_group']))
1053
		$groups = $config['gateways']['gateway_group'];
1054
	else
1055
		return false;
1056

    
1057
	$gateways_arr = return_gateways_array(false, true);
1058
	foreach($groups as $group) {
1059
		if(is_array($group['item'])) {
1060
			foreach($group['item'] as $item) {
1061
				$elements = explode("|", $item);
1062
				$gwname = $elements[0];
1063
				if ($interface == $gateways_arr[$gwname]['interface']) {
1064
					unset($gateways_arr);
1065
					return true;
1066
				}
1067
			}
1068
		}
1069
	}
1070
	unset($gateways_arr);
1071

    
1072
	return false;
1073
}
1074

    
1075
function gateway_is_gwgroup_member($name) {
1076
	global $config;
1077

    
1078
	if (is_array($config['gateways']['gateway_group']))
1079
		$groups = $config['gateways']['gateway_group'];
1080
	else
1081
		return false;
1082

    
1083
	$members = array();
1084
	foreach($groups as $group) {
1085
		if (is_array($group['item'])) {
1086
			foreach($group['item'] as $item) {
1087
				$elements = explode("|", $item);
1088
				$gwname = $elements[0];
1089
				if ($name == $elements[0])
1090
					$members[] = $group['name'];
1091
			}
1092
		}
1093
	}
1094

    
1095
	return $members;
1096
}
1097
?>
(25-25/68)