Project

General

Profile

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

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

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

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

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

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

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

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

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

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

    
60
	$apinger_default = return_apinger_defaults();
61
	$fd = fopen("{$g['varetc_path']}/apinger.conf", "w");
62
	$apingerconfig = <<<EOD
63

    
64
# pfSense apinger configuration file. Automatically Generated!
65

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

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

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

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

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

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

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

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

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

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

    
121
target default {
122
	## How often the probe should be sent	
123
	interval {$apinger_default['interval']}s
124
	
125
	## How many replies should be used to compute average delay 
126
	## for controlling "delay" alarms
127
	avg_delay_samples 10
128
	
129
	## How many probes should be used to compute average loss
130
	avg_loss_samples 50
131

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

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

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

    
143
EOD;
144

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

    
157
		/* if the monitor address is already used before, skip */ 
158
		if(in_array($gateway['monitor'], $monitor_ips))
159
			continue;
160
		
161
		/* Interface ip is needed since apinger will bind a socket to it. */
162
		if (is_ipaddrv4($gateway['gateway'])) {
163
			$gwifip = find_interface_ip($gateway['interface'], true);
164
		}
165
		if (is_ipaddrv6($gateway['gateway'])) {
166
			/* link locals really need a different src ip */
167
			if(preg_match("/fe80::/i", $gateway['gateway'])) {
168
				$linklocal = explode("%", find_interface_ipv6_ll($gateway['interface'], true));
169
				$gwifip = $linklocal[0];
170
				$ifscope = "%". $linklocal[1];
171
			} else {
172
				$gwifip = find_interface_ipv6($gateway['interface'], true);
173
			}
174
		}
175
		if (!is_ipaddr($gwifip))
176
			continue; //Skip this target
177

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

    
232
		$apingercfg .= "	rrd file \"{$g['vardb_path']}/rrd/{$gateway['name']}-quality.rrd\"\n";
233
		$apingercfg .= "}\n";
234
		$apingercfg .= "\n";
235
		/*
236
		 * If the gateway is the same as the monitor we do not add a
237
		 * route as this will break the routing table.
238
		 * Add static routes for each gateway with their monitor IP
239
		 * not strictly necessary but is a added level of protection.
240
		 */
241
		if (is_ipaddr($gateway['gateway']) && $gateway['monitor'] != $gateway['gateway']) {
242
			log_error(sprintf(gettext('Removing static route for monitor %1$s and adding a new route through %2$s'), $gateway['monitor'], $gateway['gateway']));
243
			if(is_ipaddrv6($gateway['gateway'])) {
244
				$inetfamily = "-inet6";
245
			} else {
246
				$inetfamily = "-inet";
247
			}
248
			// mwexec("/sbin/route change {$inetfamily} -host " . escapeshellarg($gateway['monitor']) .
249
			//	" " . escapeshellarg($gateway['gateway']), true);
250
		}
251

    
252
		$apingerconfig .= $alarmscfg;
253
		$apingerconfig .= $apingercfg;
254
	}
255
	fwrite($fd, $apingerconfig);
256
	fclose($fd);
257
	unset($apingerconfig);
258

    
259
	killbypid("{$g['varrun_path']}/apinger.pid");
260
	if (is_dir("{$g['tmp_path']}"))
261
		chmod("{$g['tmp_path']}", 01777);
262
	if (!is_dir("{$g['vardb_path']}/rrd"))
263
		mkdir("{$g['vardb_path']}/rrd", 0775);
264

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

    
267
	/* start a new apinger process */
268
	@unlink("{$g['tmp_path']}/apinger.status");
269
	sleep(1);
270
	mwexec_bg("/usr/local/sbin/apinger -c {$g['varetc_path']}/apinger.conf");
271

    
272
	return 0;
273
}
274

    
275
/* return the status of the apinger targets as a array */
276
function return_gateways_status($byname = false) {
277
	global $config, $g;
278

    
279
	$apingerstatus = array();
280
	if (file_exists("{$g['tmp_path']}/apinger.status")) {
281
		$apingerstatus = file("{$g['tmp_path']}/apinger.status");
282
	}
283

    
284
	$status = array();
285
	foreach($apingerstatus as $line) {
286
		$info = explode("|", $line);
287
		if ($byname == false)
288
			$target = $info[0];
289
		else
290
			$target = $info[2];
291

    
292
		$status[$target]['monitorip'] = $info[0];
293
		$status[$target]['srcip'] = $info[1];
294
		$status[$target]['name'] = $info[2];
295
		$status[$target]['lastcheck'] = $info[5] ? date('r', $info[5]) : date('r');
296
		$status[$target]['delay'] = empty($info[6]) ? "0ms" : round($info[6], 1) ."ms" ;
297
		$status[$target]['loss'] = empty($info[7]) ? "0.0%" : round($info[7], 1) . "%";
298
		$status[$target]['status'] = trim($info[8]);
299
	}
300

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

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

    
341
/* Return all configured gateways on the system */
342
function return_gateways_array($disabled = false, $localhost = false) {
343
	global $config, $g;
344

    
345
	$gateways_arr = array();
346

    
347
	$found_defaultv4 = 0;
348
	$found_defaultv6 = 0;
349

    
350
	$interfaces_v4 = array();
351
	$interfaces_v6 = array();
352

    
353
	$i = 0;
354
	/* Process/add all the configured gateways. */
355
	if (is_array($config['gateways']['gateway_item'])) {
356
		foreach($config['gateways']['gateway_item'] as $gateway) {
357
			/* skip disabled interfaces */
358
			if(!isset($config['interfaces'][$gateway['interface']]['enable']))
359
				continue;
360

    
361
			$wancfg = $config['interfaces'][$gateway['interface']];
362
			/* getting this detection right is hard at this point because we still don't
363
			 * store the address family in the gateway item */
364
			if(is_ipaddrv4($gateway['gateway']))
365
				$gateway['ipprotocol'] = "inet";
366
			if(is_ipaddrv6($gateway['gateway']))
367
				$gateway['ipprotocol'] = "inet6";
368
			if((preg_match("/dynamic/i", $gateway['gateway'])) && (!isset($gateway['ipprotocol']))) {
369
				if(is_ipaddrv4($gateway['gateway']))
370
					$gateway['ipprotocol'] = "inet";
371
				if(is_ipaddrv6($gateway['gateway']))
372
					$gateway['ipprotocol'] = "inet6";
373
			}
374
			if((preg_match("/dynamic/i", $gateway['monitor'])) && (!isset($gateway['ipprotocol']))) {
375
				if(is_ipaddrv4($gateway['monitor']))
376
					$gateway['ipprotocol'] = "inet";
377
				if(is_ipaddrv6($gateway['monitor']))
378
					$gateway['ipprotocol'] = "inet6";
379
			}
380

    
381
			/* if the gateway is dynamic and we can find the IPv4, Great! */
382
			if((empty($gateway['gateway']) || ($gateway['gateway'] == "dynamic")) && ($gateway['ipprotocol'] == "inet")) {
383
				/* we know which interfaces is dynamic, this should be made a function */
384
				switch($wancfg['ipaddr']) {
385
					case "dhcp":
386
					case "pppoe":
387
					case "pptp":
388
					case "ppp":
389
						$gateway['ipprotocol'] = "inet";
390
						$gateway['gateway'] = get_interface_gateway($gateway['interface']);
391
						if($gateway['gateway'] == "dynamic") {
392
							$dynstr = $gateway['gateway'];
393
						}
394
						/* no IP address found, set to dynamic */
395
						if(! is_ipaddrv4($gateway['gateway'])) {
396
							$gateway['gateway'] = "{$dynstr}";
397
						}
398
						$gateway['dynamic'] = true;
399
						break;
400
				}
401
			}
402

    
403
			/* if the gateway is dynamic6 and we can find the IPv6, Great! */
404
			if((empty($gateway['gateway']) || ($gateway['gateway'] == "dynamic")) && ($gateway['ipprotocol'] == "inet6")) {
405
				/* we know which interfaces is dynamic, this should be made a function, and for v6 too */
406
				switch($wancfg['ipaddrv6']) {
407
					case "6rd":
408
					case "6to4":
409
					case "dhcp6":
410
						$gateway['ipprotocol'] = "inet6";
411
						$gateway['gateway'] = get_interface_gateway_v6($gateway['interface']);
412
						if($gateway['gateway'] == "dynamic6") {
413
							$dynstr = $gateway['gateway'];
414
						}
415
						/* no IPv6 address found, set to dynamic6 */
416
						if(! is_ipaddrv6($gateway['gateway'])) {
417
							$gateway['gateway'] = "{$dynstr}";
418
						}
419
						$gateway['dynamic'] = true;
420
						break;
421
				}
422
			}
423

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

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

    
431
			/* special treatment for tunnel interfaces */
432
			if($gateway['ipprotocol'] == "inet6") {
433
				switch($wancfg['ipaddrv6']) {
434
					case "6rd":
435
					case "6to4":
436
						$gateway['interface'] = "{$gateway['interface']}_stf";
437
						break;
438
					default:
439
						$gateway['interface'] = get_real_interface($gateway['interface']);
440
						break;
441
				}
442
			}
443
			if($gateway['ipprotocol'] == "inet") {
444
				$gateway['interface'] = get_real_interface($gateway['interface']);
445
			}
446

    
447
			/* entry has a default flag, use it */
448
			if (isset($gateway['defaultgw'])) {
449
				if($gateway['ipprotocol'] == "inet") {
450
					$gateway['defaultgw'] = true;
451
					$found_defaultv4 = 1;
452
				}
453
				if($gateway['ipprotocol'] == "inet6") {
454
					$gateway['defaultgw'] = true;
455
					$found_defaultv6 = 1;
456
				}
457
			}
458
			/* include the gateway index as the attribute */
459
			$gateway['attribute'] = $i;
460

    
461
			/* tack a item on the array to keep track of dynamic interfaces */
462
			if($gateway['ipprotocol'] == "inet")
463
				$interfaces_v4[] = $gateway['friendlyiface'];
464

    
465
			if($gateway['ipprotocol'] == "inet6")
466
				$interfaces_v6[] = $gateway['friendlyiface'];
467

    
468
			$gateways_arr[$gateway['name']] = $gateway;
469
			unset($gateway);
470
			$i++;
471
		}
472
	}
473

    
474
	/* Loop through all interfaces with a gateway and add it to a array */
475
	if ($disabled == false)
476
		$iflist = get_configured_interface_with_descr();
477
	else
478
		$iflist = get_configured_interface_with_descr(false, true);
479

    
480
	/* Process/add dynamic v4 gateways. */
481
	foreach($iflist as $ifname => $friendly ) {
482
		if(! interface_has_gateway($ifname))
483
			continue;
484

    
485
		if (empty($config['interfaces'][$ifname]))
486
			continue;
487

    
488
		$ifcfg = &$config['interfaces'][$ifname];
489
		if(!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr']))
490
			continue;
491

    
492
		if(!isset($ifcfg['enable']))
493
			continue;
494

    
495
		if(in_array($ifname, $interfaces_v4))
496
			continue;
497
			
498
		$ctype = "";
499
		switch($ifcfg['ipaddr']) {
500
			case "dhcp":
501
			case "pppoe":
502
			case "pptp":
503
			case "ppp":
504
				$ctype = strtoupper($ifcfg['ipaddr']);
505
				break;
506
			default:
507
				if (substr($ifcfg['if'], 0, 4) ==  "ovpn")
508
					$ctype = "VPNv4";
509
				break;
510
		}
511
		$ctype = "_". strtoupper($ctype);
512

    
513
		$gateway = array();
514
		$gateway['dynamic'] = false;
515
		$gateway['ipprotocol'] = "inet";
516
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
517
		$gateway['interface'] = get_real_interface($ifname);
518
		$gateway['friendlyiface'] = $ifname;
519
		$gateway['name'] = "{$friendly}{$ctype}";
520
		$gateway['attribute'] = "system";
521
	
522
		if (($gateway['dynamic'] === "default") && ($found_defaultv4 == 0)) {
523
			$gateway['defaultgw'] = true;
524
			$gateway['dynamic'] = true;
525
			$found_defaultv4 = 1;
526
		}
527
		/* Loopback dummy for dynamic interfaces without a IP */
528
		if (!is_ipaddrv4($gateway['gateway']) && $gateway['dynamic'] == true)
529
			$gateway['gateway'] = "dynamic";
530

    
531
		/* automatically skip known static and dynamic gateways we have a array entry for */
532
		foreach($gateways_arr as $gateway_item) {
533
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name'])&& ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
534
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
535
					continue 2;
536
		}
537

    
538
		if (is_ipaddrv4($gateway['gateway']))
539
			$gateway['monitor'] = $gateway['gateway'];
540

    
541
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
542
		$gateways_arr[$gateway['name']] = $gateway;
543
		unset($gateway);
544
	}
545

    
546
	/* Process/add dynamic v6 gateways. */
547
	foreach($iflist as $ifname => $friendly ) {
548
		/* If the user has disabled IPv6, they probably don't want any IPv6 gateways. */
549
		if (!isset($config['system']['ipv6allow']))
550
			break;
551

    
552
		if(! interface_has_gatewayv6($ifname))
553
			continue;
554

    
555
		if (empty($config['interfaces'][$ifname]))
556
			continue;
557

    
558
		$ifcfg = &$config['interfaces'][$ifname];
559
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
560
			continue;
561
			
562
		if(!isset($ifcfg['enable']))
563
			continue;
564

    
565
		if(in_array($ifname, $interfaces_v6))
566
			continue;
567

    
568
		$ctype = "";
569
		switch($ifcfg['ipaddrv6']) {
570
			case "slaac":
571
			case "dhcp6":
572
			case "6to4":
573
			case "6rd":
574
				$ctype = strtoupper($ifcfg['ipaddrv6']);
575
				break;
576
			default:
577
				if (substr($ifcfg['if'], 0, 4) ==  "ovpn")
578
					$ctype = "VPNv6";
579
				break;
580
		}
581
		$ctype = "_". strtoupper($ctype);
582

    
583
		$gateway = array();
584
		$gateway['dynamic'] = false;
585
		$gateway['ipprotocol'] = "inet6";
586
		$gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
587
		switch($ifcfg['ipaddrv6']) {
588
			case "6to4":
589
				$gateway['interface'] = "{$ifname}_stf";
590
				$gateway['dynamic'] = "default";
591
				break;
592
			case "6rd":
593
				$gateway['interface'] = "{$ifname}_stf";
594
				$gateway['dynamic'] = "default";
595
				break;
596
			default:
597
				$gateway['interface'] = get_real_interface($ifname);
598
				break;
599
		}
600
		$gateway['friendlyiface'] = $ifname;
601
		$gateway['name'] = "{$friendly}{$ctype}";
602
		$gateway['attribute'] = "system";
603
	
604
		if (($gateway['dynamic'] === "default")  && ($found_defaultv6 == 0)) {
605
			$gateway['defaultgw'] = true;
606
			$gateway['dynamic'] = true;
607
			$found_defaultv6 = 1;
608
		}
609

    
610
		/* Loopback dummy for dynamic interfaces without a IP */
611
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
612
			$gateway['gateway'] = "dynamic6";
613

    
614
		/* automatically skip known static and dynamic gateways we have a array entry for */
615
		foreach($gateways_arr as $gateway_item) {
616
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
617
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
618
					continue 2;
619
		}
620

    
621
		if (is_ipaddrv6($gateway['gateway']))
622
			$gateway['monitor'] = $gateway['gateway'];
623

    
624
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
625
		$gateways_arr[$gateway['name']] = $gateway;
626
		unset($gateway);
627
	}
628

    
629
	/* FIXME: Should this be enabled.
630
	 * Some interface like wan might be default but have no info recorded
631
	 * the config. */
632
	/* this is a fallback if all else fails and we want to get packets out @smos */
633
	if ($found_defaultv4 == 0 || $found_defaultv6 == 0) {
634
		foreach ($gateways_arr as &$gateway) {
635
			if (($gateway['friendlyiface'] == "wan") && ($found_defaultv4 == 0) && (!isset($gateway['ipprotocol']) || ($gateway['ipprotocol'] == "inet"))) {
636
				if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgw")) {
637
					$gateway['defaultgw'] = true;
638
					$found_defaultv4 = 1;
639
				}
640
			}
641
			if (($gateway['friendlyiface'] == "wan") && ($found_defaultv6 == 0) && ($gateway['ipprotocol'] == "inet6")) {
642
				if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgwv6")) {
643
					$gateway['defaultgw'] = true;
644
					$found_defaultv6 = 1;
645
				}
646
			}
647
		}
648
	}
649

    
650
	if($localhost === true) {
651
		/* attach localhost for Null routes */
652
		$gwlo4 = array();
653
		$gwlo4['name'] = "Null4";
654
		$gwlo4['interface'] = "lo0";
655
		$gwlo4['ipprotocol'] = "inet";
656
		$gwlo4['gateway'] = "127.0.0.1";
657
		$gwlo6 = array();
658
		$gwlo6['name'] = "Null6";
659
		$gwlo6['interface'] = "lo0";
660
		$gwlo6['ipprotocol'] = "inet6";
661
		$gwlo6['gateway'] = "::1";
662
		$gateways_arr['Null4'] = $gwlo4;
663
		$gateways_arr['Null6'] = $gwlo6;
664
	}
665
	return($gateways_arr);
666
}
667

    
668
function fixup_default_gateway($ipprotocol, $gateways_status, $gateways_arr) {
669
	global $config, $g;
670
	/*
671
	 * NOTE: The code below is meant to replace the default gateway when it goes down.
672
	 *	This facilitates services running on pfSense itself and are not handled by a PBR to continue working.
673
	 */
674
	$upgw = "";
675
	$dfltgwdown = false;
676
	$dfltgwfound = false;
677
	foreach ($gateways_arr as $gwname => $gwsttng) {
678
		if (($gwsttng['ipprotocol'] == $ipprotocol) && isset($gwsttng['defaultgw'])) {
679
			$dfltgwfound = true;
680
			$dfltgwname = $gwname;
681
			if (!isset($gwsttng['monitor_disable']) && stristr($gateways_status[$gwname]['status'], "down"))
682
				$dfltgwdown = true;
683
		}
684
		/* Keep a record of the last up gateway */
685
		/* XXX: Blacklist lan for now since it might cause issues to those who have a gateway set for it */
686
		if (empty($upgw) && ($gwsttng['ipprotocol'] == $ipprotocol) && (isset($gwsttng['monitor_disable']) || !stristr($gateways_status[$gwname]['status'], "down")) && $gwsttng[$gwname]['friendlyiface'] != "lan")
687
			$upgw = $gwname;
688
		if ($dfltgwdown == true && !empty($upgw))
689
			break;
690
	}
691
	if ($dfltgwfound == false) {
692
		$gwname = convert_friendly_interface_to_friendly_descr("wan");
693
		if (!empty($gateways_status[$gwname]) && stristr($gateways_status[$gwname]['status'], "down"))
694
			$dfltgwdown = true;
695
	}
696
	if ($dfltgwdown == true && !empty($upgw)) {
697
		if (preg_match("/dynamic/i", $gateways_arr[$upgw]['gateway']))
698
			$gateways_arr[$upgw]['gateway'] = get_interface_gateway($gateways_arr[$upgw]['friendlyiface']);
699
		if (is_ipaddr($gateways_arr[$upgw]['gateway'])) {
700
			log_error("Default gateway down setting {$upgw} as default!");
701
			if(is_ipaddrv6($gateways_arr[$upgw]['gateway'])) {
702
				$inetfamily = "-inet6";
703
			} else {
704
				$inetfamily = "-inet";
705
			}
706
			mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$upgw]['gateway']}");
707
		}
708
	} else {
709
		$defaultgw = trim(`/sbin/route -n get -{$ipprotocol} default | /usr/bin/grep gateway | /usr/bin/sed 's/gateway://g'`, " \n");
710
		if(is_ipaddrv6($gateways_arr[$dfltgwname]['gateway'])) {
711
			$inetfamily = "-inet6";
712
		} else {
713
			$inetfamily = "-inet";
714
		}
715
		if ($defaultgw != $gateways_arr[$dfltgwname]['gateway'])
716
			mwexec("/sbin/route change {$inetfamily} default {$gateways_arr[$dfltgwname]['gateway']}");
717
	}
718
}
719

    
720
/*
721
 * Return an array with all gateway groups with name as key
722
 * All gateway groups will be processed before returning the array.
723
 */
724
function return_gateway_groups_array() {
725
	global $config, $g;
726

    
727
	/* fetch the current gateways status */
728
	$gateways_status = return_gateways_status(true);
729
	$gateways_arr = return_gateways_array();
730
	$gateway_groups_array = array();
731
	$carplist = get_configured_carp_interface_list();
732

    
733
	if (isset($config['system']['gw_switch_default'])) {
734
		fixup_default_gateway("inet", $gateways_status, $gateways_arr);
735
		fixup_default_gateway("inet6", $gateways_status, $gateways_arr);
736
	}
737
	if (is_array($config['gateways']['gateway_group'])) {
738
		foreach($config['gateways']['gateway_group'] as $group) {
739
			/* create array with group gateways members seperated by tier */
740
			$tiers = array();
741
			$backupplan = array();
742
			foreach($group['item'] as $item) {
743
				$itemsplit = explode("|", $item);
744
				$tier = $itemsplit[1];
745
				$gwname = $itemsplit[0];
746
				$vipname = $itemsplit[2];
747
				if(is_ipaddr($carplist[$vipname]))
748
					$gwvip_arr[$group['name']][$gwname] = $vipname;
749

    
750
				/* Do it here rather than reiterating again the group in case no member is up. */
751
				$backupplan[$tier][] = $gwname;
752

    
753
				/* check if the gateway is available before adding it to the array */
754
				if (is_array($gateways_status[$gwname])) {
755
					$status = $gateways_status[$gwname];
756
					$gwdown = false;
757
					if (stristr($status['status'], "down")) {
758
						$msg = sprintf(gettext("MONITOR: %s is down, removing from routing group {$group['name']}"), $gwname);
759
						$gwdown = true;
760
					} else if (stristr($status['status'], "loss") && strstr($group['trigger'], "loss")) {
761
						/* packet loss */
762
						$msg = sprintf(gettext("MONITOR: %s has packet loss, removing from routing group {$group['name']}"), $gwname);
763
						$gwdown = true;
764
					} else if (stristr($status['status'], "delay") && strstr($group['trigger'] , "latency")) {
765
						/* high latency */
766
						$msg = sprintf(gettext("MONITOR: %s has high latency, removing from routing group {$group['name']}"), $gwname);
767
						$gwdown = true;
768
					}
769
					if ($gwdown == true) {
770
						log_error($msg);
771
						notify_via_growl($msg);
772
						notify_via_smtp($msg);
773
					} else {
774
						/* Online add member */
775
						$tiers[$tier][] = $gwname;
776
					}
777
				} else if (isset($gateways_arr[$gwname]['monitor_disable']))
778
					$tiers[$tier][] = $gwname;
779
			}
780
			$tiers_count = count($tiers);
781
			if($tiers_count == 0) {
782
				/* Oh dear, we have no members! Engage Plan B */
783
				if (!$g['booting']) {
784
					$msg = gettext("Gateways status could not be determined, considering all as up/active. (Group: {$group['name']})");
785
					log_error($msg);
786
					notify_via_growl($msg);
787
					//notify_via_smtp($msg);
788
				}
789
				$tiers = $backupplan;
790
			}
791
			/* sort the tiers array by the tier key */
792
			ksort($tiers);
793

    
794
			/* we do not really foreach the tiers as we stop after the first tier */
795
			foreach($tiers as $tier) {
796
				/* process all gateways in this tier */
797
				foreach($tier as $member) {
798
					/* determine interface gateway */
799
					if (isset($gateways_arr[$member])) {
800
						$gateway = $gateways_arr[$member];
801
						$int = $gateway['interface'];
802
						$gatewayip = "";
803
						if(is_ipaddr($gateway['gateway'])) 
804
							$gatewayip = $gateway['gateway'];
805
						else if ($int <> "")
806
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
807
					
808
						if (($int <> "") && is_ipaddr($gatewayip)) {
809
							$groupmember = array();
810
							$groupmember['int']  = $int;
811
							$groupmember['gwip']  = $gatewayip;
812
							$groupmember['weight']  = isset($gateway['weight']) ? $gateway['weight'] : 1;
813
							if($gwvip_arr[$group['name']][$gwname] <> "")
814
								$groupmember['vip'] = $gwvip_arr[$group['name']][$gwname];
815
							$gateway_groups_array[$group['name']]['ipprotocol'] = $gateway['ipprotocol'];
816
							$gateway_groups_array[$group['name']][] = $groupmember;
817
						}
818
					}
819
				}
820
				/* we should have the 1st available tier now, exit stage left */
821
				if(is_array($gateway_groups_array[$group['name']]))
822
					break;
823
				else
824
					log_error("GATEWAYS: We did not find the first tier of the gateway group {$group['name']}! That's odd.");
825
			}
826
		}
827
	}
828
	return ($gateway_groups_array);
829
}
830

    
831
/* Update DHCP WAN Interface ip address in gateway group item */
832
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
833
	global $config, $g;
834
	foreach($config['gateways']['gateway_item'] as & $gw) {	
835
		if($gw['interface'] == $interface) {
836
			$current_gw = get_interface_gateway($interface);
837
			if($gw['gateway'] <> $current_gw) {
838
				$gw['gateway'] = $current_gw;
839
				$changed = true;
840
			}
841
		}
842
	}
843
	if($changed && $current_gw)
844
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interfac, $current_gw));
845
}
846

    
847
function lookup_gateway_ip_by_name($name) {
848

    
849
	$gateways_arr = return_gateways_array(false, true);
850
        foreach ($gateways_arr as $gname => $gw) {
851
                if ($gw['name'] == $name || $gname == $name)
852
                        return $gw['gateway'];
853
        }
854

    
855
	return false;
856
}
857

    
858
function lookup_gateway_monitor_ip_by_name($name) {
859

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

    
866
		return $gateway['monitor'];
867
        }
868

    
869
        return (false);
870
}
871

    
872
function lookup_gateway_interface_by_name($name) {
873

    
874
        $gateways_arr = return_gateways_array(false, true);
875
	if (!empty($gateways_arr[$name])) {
876
		$interfacegw = $gateways_arr[$name]['interface'];
877
		return ($interfacegw);
878
        }
879

    
880
        return (false);
881
}
882

    
883
function get_interface_gateway($interface, &$dynamic = false) {
884
	global $config, $g;
885

    
886
	$gw = NULL;
887

    
888
	$gwcfg = $config['interfaces'][$interface];
889
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
890
		foreach($config['gateways']['gateway_item'] as $gateway) {
891
			if(($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
892
				$gw = $gateway['gateway'];
893
				break;
894
			}
895
		}
896
	}
897

    
898
	// for dynamic interfaces we handle them through the $interface_router file.
899
	if (!is_ipaddrv4($gw) && !is_ipaddrv4($gwcfg['ipaddr'])) {
900
		$realif = get_real_interface($interface);
901
		if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
902
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
903
			$dynamic = true;
904
		}
905
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw"))
906
			$dynamic = "default";
907
			
908
	}
909

    
910
	/* return gateway */
911
	return ($gw);
912
}
913

    
914
function get_interface_gateway_v6($interface, &$dynamic = false) {
915
	global $config, $g;
916

    
917
	$gw = NULL;
918
	$gwcfg = $config['interfaces'][$interface];
919
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
920
		foreach($config['gateways']['gateway_item'] as $gateway) {
921
			if(($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
922
				$gw = $gateway['gateway'];
923
				break;
924
			}
925
		}
926
	}
927

    
928
	// for dynamic interfaces we handle them through the $interface_router file.
929
	if (!is_ipaddrv6($gw) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
930
			$realif = get_real_interface($interface);
931
			if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
932
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
933
				$dynamic = true;
934
			}
935
			if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6"))
936
				$dynamic = "default";
937
			
938
	}
939
	/* return gateway */
940
	return ($gw);
941
}
942

    
943
/* Check a IP address against a gateway IP or name
944
 * to verify it's address family */
945
function validate_address_family($ipaddr, $gwname) {
946
	$v4ip = false;
947
	$v6ip = false;
948
	$v4gw = false;
949
	$v6gw = false;
950

    
951
	if(is_ipaddrv4($ipaddr))
952
		$v4ip = true;
953
	if(is_ipaddrv6($ipaddr))
954
		$v6ip = true;
955
	if(is_ipaddrv4($gwname))
956
		$v4gw = true;
957
	if(is_ipaddrv6($gwname))
958
		$v6gw = true;
959

    
960
	if($v4ip && $v4gw)
961
		return true;
962
	if($v6ip && $v6gw)
963
		return true;
964

    
965
	/* still no match, carry on, lookup gateways */
966
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
967
		$v4gw = true;
968
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
969
		$v6gw = true;
970

    
971
	$gw_array = return_gateways_array();
972
	if(is_array($gw_array[$gwname])) {
973
		switch($gw_array[$gwname]['ipprotocol']) {
974
			case "inet":
975
				$v4gw = true;
976
				break;
977
			case "inet6":
978
				$v6gw = true;
979
				break;
980
		}
981
	}
982

    
983
	if($v4ip && $v4gw)
984
		return true;
985
	if($v6ip && $v6gw)
986
		return true;
987
	
988
	return false;
989
}
990

    
991
/* check if a interface is part of a gateway group */
992
function interface_gateway_group_member($interface) {
993
	global $config;
994
	$realif = get_real_interface($interface);
995
	if(is_array($config['gateways']['gateway_group']))
996
		$groups = $config['gateways']['gateway_group'];
997
	else
998
		return false;
999

    
1000
	foreach($groups as $group) {
1001
		if(is_array($group['item'])) {
1002
			foreach($group['item'] as $item) {
1003
				$elements = explode("|", $item);
1004
				$gwname = $elements[0];
1005
				$gwif = get_real_interface(lookup_gateway_interface_by_name($gwname));
1006
				if($gwif == $realif)
1007
					return true;
1008
			}
1009
		}
1010
	}
1011
	return false;
1012
}
1013

    
1014
?>
(24-24/66)