Project

General

Profile

Download (29.9 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
/*
35
 * Creates monitoring configuration file and
36
 * adds apropriate static routes.
37
 */
38
function setup_gateways_monitor() {
39
	global $config, $g;
40

    
41
	$gateways_arr = return_gateways_array();
42
	if (!is_array($gateways_arr)) {
43
		log_error("No gateways to monitor. Apinger will not be run.");
44
		killbypid("{$g['varrun_path']}/apinger.pid");
45
		@unlink("{$g['tmp_path']}/apinger.status");
46
		return;
47
	}
48

    
49
	/* Default settings. Probably should move to globals.inc? */
50
	$a_settings = array();
51
	$a_settings['latencylow'] = "200";
52
	$a_settings['latencyhigh'] = "500";
53
	$a_settings['losslow'] = "10";
54
	$a_settings['losshigh'] = "20";
55

    
56
	$fd = fopen("{$g['varetc_path']}/apinger.conf", "w");
57
	$apingerconfig = <<<EOD
58

    
59
# pfSense apinger configuration file. Automatically Generated!
60

    
61
## User and group the pinger should run as
62
user "root"
63
group "wheel"
64

    
65
## Mailer to use (default: "/usr/lib/sendmail -t")
66
#mailer "/var/qmail/bin/qmail-inject" 
67

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

    
71
## Format of timestamp (%s macro) (default: "%b %d %H:%M:%S")
72
#timestamp_format "%Y%m%d%H%M%S"
73

    
74
status {
75
	## File where the status information whould be written to
76
	file "{$g['tmp_path']}/apinger.status"
77
	## Interval between file updates
78
	## when 0 or not set, file is written only when SIGUSR1 is received
79
	interval 5s
80
}
81

    
82
########################################
83
# RRDTool status gathering configuration
84
# Interval between RRD updates
85
rrd interval 60s;
86

    
87
## These parameters can be overriden in a specific alarm configuration
88
alarm default { 
89
	command on "/usr/local/sbin/pfSctl -c 'filter reload'"
90
	command off "/usr/local/sbin/pfSctl -c 'filter reload'"
91
	combine 10s
92
}
93

    
94
## "Down" alarm definition. 
95
## This alarm will be fired when target doesn't respond for 30 seconds.
96
alarm down "down" {
97
	time 10s
98
}
99

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

    
108
## "Loss" alarm definition. 
109
## This alarm will be fired when packet loss goes over 20%
110
## it will be canceled, when the loss drops below 10%
111
alarm loss "loss" {
112
	percent_low {$a_settings['losslow']}
113
	percent_high {$a_settings['losshigh']}
114
}
115

    
116
target default {
117
	## How often the probe should be sent	
118
	interval 1s
119
	
120
	## How many replies should be used to compute average delay 
121
	## for controlling "delay" alarms
122
	avg_delay_samples 10
123
	
124
	## How many probes should be used to compute average loss
125
	avg_loss_samples 50
126

    
127
	## The delay (in samples) after which loss is computed
128
	## without this delays larger than interval would be treated as loss
129
	avg_loss_delay_samples 20
130

    
131
	## Names of the alarms that may be generated for the target
132
	alarms "down","delay","loss"
133

    
134
	## Location of the RRD
135
	#rrd file "{$g['vardb_path']}/rrd/apinger-%t.rrd"
136
}
137

    
138
EOD;
139

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

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

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

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

    
247
		$apingerconfig .= $alarmscfg;
248
		$apingerconfig .= $apingercfg;
249
	}
250
	fwrite($fd, $apingerconfig);
251
	fclose($fd);
252

    
253
	killbypid("{$g['varrun_path']}/apinger.pid");
254
	if (is_dir("{$g['tmp_path']}"))
255
		chmod("{$g['tmp_path']}", 01777);
256
	if (!is_dir("{$g['vardb_path']}/rrd"))
257
		mkdir("{$g['vardb_path']}/rrd", 0775);
258

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

    
261
	/* start a new apinger process */
262
	@unlink("{$g['tmp_path']}/apinger.status");
263
	sleep(1);
264
	mwexec_bg("/usr/local/sbin/apinger -c {$g['varetc_path']}/apinger.conf");
265

    
266
	return 0;
267
}
268

    
269
/* return the status of the apinger targets as a array */
270
function return_gateways_status($byname = false) {
271
	global $config, $g;
272

    
273
	$apingerstatus = array();
274
	if (file_exists("{$g['tmp_path']}/apinger.status")) {
275
		$apingerstatus = file("{$g['tmp_path']}/apinger.status");
276
	}
277

    
278
	$status = array();
279
	foreach($apingerstatus as $line) {
280
		$info = explode("|", $line);
281
		if ($byname == false)
282
			$target = $info[0];
283
		else
284
			$target = $info[2];
285
		$status[$target]['monitorip'] = $info[0];
286
		$status[$target]['srcip'] = $info[1];
287
		$status[$target]['name'] = $info[2];
288
		$status[$target]['lastcheck'] = $info[5] ? date('r', $info[5]) : date('r');
289
		$status[$target]['delay'] = empty($info[6]) ? 0 : $info[6];
290
		$status[$target]['loss'] = empty($info[7]) ? "0.0%" : $info[7] . "";
291
		$status[$target]['status'] = trim($info[8]);
292
	}
293

    
294
	/* tack on any gateways that have monitoring disabled */
295
	$gateways_arr = return_gateways_array();
296
	foreach($gateways_arr as $gwitem) {
297
		if(isset($gwitem['monitor_disable'])) {
298
			if(!is_ipaddr($gwitem['monitorip'])) {
299
				$realif = $gwitem['interface'];
300
				$tgtip = get_interface_gateway($realif);
301
				$srcip = find_interface_ip($realif);
302
			} else {
303
				$tgtip = $gwitem['monitorip'];
304
				$srcip = find_interface_ip($realif);
305
			}
306
			if($byname == true)
307
				$target = $gwitem['name'];
308
			else
309
				$target = $tgtip;
310

    
311
			$status[$target]['monitorip'] = $tgtip;
312
			$status[$target]['srcip'] = $srcip;
313
			$status[$target]['name'] = $gwitem['name'];
314
			$status[$target]['lastcheck'] = date('r');
315
			$status[$target]['delay'] = "0.0ms";
316
			$status[$target]['loss'] = "0.0%";
317
			$status[$target]['status'] = "none";
318
		}
319
	}
320
	return($status);
321
}
322

    
323
/* Return all configured gateways on the system */
324
function return_gateways_array($disabled = false, $localhost = false) {
325
	global $config, $g;
326

    
327
	$gateways_arr = array();
328

    
329
	$found_defaultv4 = 0;
330
	$found_defaultv6 = 0;
331

    
332
	$interfaces_v4 = array();
333
	$interfaces_v6 = array();
334

    
335
	$i = 0;
336
	/* Process/add all the configured gateways. */
337
	if (is_array($config['gateways']['gateway_item'])) {
338
		foreach($config['gateways']['gateway_item'] as $gateway) {
339
			/* skip disabled interfaces */
340
			if(!isset($config['interfaces'][$gateway['interface']]['enable']))
341
				continue;
342

    
343
			$wancfg = $config['interfaces'][$gateway['interface']];
344
			/* getting this detection right is hard at this point because we still don't
345
			 * store the address family in the gateway item */
346
			if(is_ipaddrv4($gateway['gateway']))
347
				$gateway['ipprotocol'] = "inet";
348
			if(is_ipaddrv6($gateway['gateway']))
349
				$gateway['ipprotocol'] = "inet6";
350
			if((preg_match("/dynamic/i", $gateway['gateway'])) && (!isset($gateway['ipprotocol']))) {
351
				if(is_ipaddrv4($gateway['gateway']))
352
					$gateway['ipprotocol'] = "inet";
353
				if(is_ipaddrv6($gateway['gateway']))
354
					$gateway['ipprotocol'] = "inet6";
355
			}
356
			if((preg_match("/dynamic/i", $gateway['monitor'])) && (!isset($gateway['ipprotocol']))) {
357
				if(is_ipaddrv4($gateway['monitor']))
358
					$gateway['ipprotocol'] = "inet";
359
				if(is_ipaddrv6($gateway['monitor']))
360
					$gateway['ipprotocol'] = "inet6";
361
			}
362

    
363
			/* if the gateway is dynamic and we can find the IPv4, Great! */
364
			if(empty($gateway['gateway']) || ($gateway['gateway'] == "dynamic") && ($gateway['ipprotocol'] == "inet")) {
365
				/* we know which interfaces is dynamic, this should be made a function */
366
				switch($wancfg['ipaddr']) {
367
					case "dhcp":
368
					case "pppoe":
369
					case "pptp":
370
					case "ppp":
371
						$gateway['ipprotocol'] = "inet";
372
						$gateway['gateway'] = get_interface_gateway($gateway['interface']);
373
						if($gateway['gateway'] == "dynamic") {
374
							$dynstr = $gateway['gateway'];
375
						}
376
						/* no IP address found, set to dynamic */
377
						if(! is_ipaddrv4($gateway['gateway'])) {
378
							$gateway['gateway'] = "{$dynstr}";
379
						}
380
						$gateway['dynamic'] = true;
381
						break;
382
				}
383
			}
384

    
385
			/* if the gateway is dynamic6 and we can find the IPv6, Great! */
386
			if(empty($gateway['gateway']) || ($gateway['gateway'] == "dynamic")  && ($gateway['ipprotocol'] == "inet6")) {
387
				/* we know which interfaces is dynamic, this should be made a function, and for v6 too */
388
				switch($wancfg['ipaddrv6']) {
389
					case "6rd":
390
					case "6to4":
391
					case "dhcp6":
392
						$gateway['ipprotocol'] = "inet6";
393
						$gateway['gateway'] = get_interface_gateway_v6($gateway['interface']);
394
						if($gateway['gateway'] == "dynamic6") {
395
							$dynstr = $gateway['gateway'];
396
						}
397
						/* no IPv6 address found, set to dynamic6 */
398
						if(! is_ipaddrv6($gateway['gateway'])) {
399
							$gateway['gateway'] = "{$dynstr}";
400
						}
401
						$gateway['dynamic'] = true;
402
						break;
403
				}
404
			}
405

    
406
			if (isset($gateway['monitor_disable']))
407
				$gateway['monitor_disable'] = true;
408
			else if (empty($gateway['monitor']))
409
				$gateway['monitor'] = $gateway['gateway'];
410

    
411
			$gateway['friendlyiface'] = $gateway['interface'];
412

    
413
			/* special treatment for tunnel interfaces */
414
			if($gateway['ipprotocol'] == "inet6") {
415
				switch($wancfg['ipaddrv6']) {
416
					case "6rd":
417
					case "6to4":
418
						$gateway['interface'] = "stf0";
419
						break;
420
				}
421
			}
422
			if($gateway['ipprotocol'] == "inet") {
423
				$gateway['interface'] = get_real_interface($gateway['interface']);
424
			}
425

    
426
			/* entry has a default flag, use it */
427
			if (isset($gateway['defaultgw'])) {
428
				if($gateway['ipprotocol'] == "inet") {
429
					$gateway['defaultgw'] = true;
430
					$found_defaultv4 = 1;
431
				}
432
				if($gateway['ipprotocol'] == "inet6") {
433
					$gateway['defaultgw'] = true;
434
					$found_defaultv6 = 1;
435
				}
436
			}
437
			/* FIXME: Should this be enabled.
438
			 * Some interface like wan might be default but have no info recorded 
439
			 * the config. */
440
			/* this is a fallback if all else fails and we want to get packets out @smos */
441
			if (!isset($gateway['defaultgw'])) {
442
				if (($gateway['friendlyiface'] == "wan") && ($found_defaultv4 == 0)) {
443
					if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgw")) {
444
						$gateway['defaultgw'] = true;
445
						$found_defaultv4 = 1;
446
					}
447
				}
448
				if (($gateway['friendlyiface'] == "wan") && ($found_defaultv6 == 0)) {
449
					if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgwv6")) {
450
						$gateway['defaultgw'] = true;
451
						$found_defaultv6 = 1;
452
					}
453
				}
454
			}
455
			/* include the gateway index as the attribute */
456
			$gateway['attribute'] = $i;
457

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

    
462
			if($gateway['ipprotocol'] == "inet6")
463
				$interfaces_v6[] = $gateway['friendlyiface'];
464

    
465
			$gateways_arr[$gateway['name']] = $gateway;
466
			unset($gateway);
467
			$i++;
468
		}
469
	}
470

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

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

    
482
		if (empty($config['interfaces'][$ifname]))
483
			continue;
484

    
485
		$ifcfg = &$config['interfaces'][$ifname];
486
		if(!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr']))
487
			continue;
488

    
489
		if(!isset($ifcfg['enable']))
490
			continue;
491

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

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

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

    
535
		if (is_ipaddrv4($gateway['gateway']))
536
			$gateway['monitor'] = $gateway['gateway'];
537

    
538
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
539
		$gateways_arr[$gateway['name']] = $gateway;
540
		unset($gateway);
541
	}
542

    
543
	/* Process/add dynamic v6 gateways. */
544
	foreach($iflist as $ifname => $friendly ) {
545
		if(! interface_has_gatewayv6($ifname))
546
			continue;
547

    
548
		if (empty($config['interfaces'][$ifname]))
549
			continue;
550

    
551
		$ifcfg = &$config['interfaces'][$ifname];
552
		if(!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6']))
553
			continue;
554
			
555
		if(!isset($ifcfg['enable']))
556
			continue;
557

    
558
		if(in_array($ifname, $interfaces_v6))
559
			continue;
560

    
561
		$ctype = "";
562
		switch($ifcfg['ipaddrv6']) {
563
			case "slaac":
564
			case "dhcp6":
565
			case "6to4":
566
			case "6rd":
567
				$ctype = strtoupper($ifcfg['ipaddrv6']);
568
				break;
569
			default:
570
				if (substr($ifcfg['if'], 0, 5) ==  "ovpnc")
571
					$ctype = "VPNv6";
572
				break;
573
		}
574
		$ctype = "_". strtoupper($ctype);
575

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

    
603
		/* Loopback dummy for dynamic interfaces without a IP */
604
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true)
605
			$gateway['gateway'] = "dynamic6";
606

    
607
		/* automatically skip known static and dynamic gateways we have a array entry for */
608
		foreach($gateways_arr as $gateway_item) {
609
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
610
				($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))
611
					continue 2;
612
		}
613

    
614
		if (is_ipaddrv6($gateway['gateway']))
615
			$gateway['monitor'] = $gateway['gateway'];
616

    
617
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
618
		$gateways_arr[$gateway['name']] = $gateway;
619
		unset($gateway);
620
	}
621

    
622
	if($localhost === true) {
623
		/* attach localhost for Null routes */
624
		$gwlo4 = array();
625
		$gwlo4['name'] = "Null4";
626
		$gwlo4['interface'] = "lo0";
627
		$gwlo4['ipprotocol'] = "inet";
628
		$gwlo4['gateway'] = "127.0.0.1";
629
		$gwlo6 = array();
630
		$gwlo6['name'] = "Null6";
631
		$gwlo6['interface'] = "lo0";
632
		$gwlo6['ipprotocol'] = "inet6";
633
		$gwlo6['gateway'] = "::1";
634
		$gateways_arr['Null4'] = $gwlo4;
635
		$gateways_arr['Null6'] = $gwlo6;
636
	}
637
	return($gateways_arr);
638
}
639

    
640
/*
641
 * Return an array with all gateway groups with name as key
642
 * All gateway groups will be processed before returning the array.
643
 */
644
function return_gateway_groups_array() {
645
	global $config, $g;
646

    
647
	/* fetch the current gateways status */
648
	$gateways_status = return_gateways_status(true);
649
	$gateways_arr = return_gateways_array();
650
	$gateway_groups_array = array();
651
	$carplist = get_configured_carp_interface_list();
652

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

    
706
	if (is_array($config['gateways']['gateway_group'])) {
707
		foreach($config['gateways']['gateway_group'] as $group) {
708
			/* create array with group gateways members seperated by tier */
709
			$tiers = array();
710
			$backupplan = array();
711
			foreach($group['item'] as $item) {
712
				$itemsplit = explode("|", $item);
713
				$tier = $itemsplit[1];
714
				$gwname = $itemsplit[0];
715
				$vipname = $itemsplit[2];
716
				if(is_ipaddr($carplist[$vipname]))
717
					$gwvip_arr[$group['name']][$gwname] = $vipname;
718

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

    
722
				/* check if the gateway is available before adding it to the array */
723
				if (!empty($gateways_status[$gwname])) {
724
					$status = $gateways_status[$gwname];
725
					$gwdown = false;
726
					if (stristr($status['status'], "down")) {
727
						$msg = sprintf(gettext("MONITOR: %s is down, removing from routing group"), $gwname);
728
						$gwdown = true;
729
					} else if (stristr($status['status'], "loss") && strstr($group['trigger'], "loss")) {
730
						/* packet loss */
731
						$msg = sprintf(gettext("MONITOR: %s has packet loss, removing from routing group"), $gwname);
732
						$gwdown = true;
733
					} else if (stristr($status['status'], "delay") && strstr($group['trigger'] , "latency")) {
734
						/* high latency */
735
						$msg = sprintf(gettext("MONITOR: %s has high latency, removing from routing group"), $gwname);
736
						$gwdown = true;
737
					}
738
					if ($gwdown == true) {
739
						log_error($msg);
740
						notify_via_growl($msg);
741
						notify_via_smtp($msg);
742
					} else
743
						/* Online add member */
744
						$tiers[$tier][] = $gwname;
745
				} else if (isset($gateways_arr[$gwname]['monitor_disable']))
746
					$tiers[$tier][] = $gwname;
747
			}
748
			$tiers_count = count($tiers);
749
			if($tiers_count == 0) {
750
				/* Oh dear, we have no members! Engage Plan B */
751
				if (!$g['booting']) {
752
					$msg = gettext("Gateways status could not be determined, considering all as up/active.");
753
					log_error($msg);
754
					notify_via_growl($msg);
755
					notify_via_smtp($msg);
756
				}
757
				$tiers = $backupplan;
758
			}
759
			/* sort the tiers array by the tier key */
760
			ksort($tiers);
761

    
762
			/* we do not really foreach the tiers as we stop after the first tier */
763
			foreach($tiers as $tier) {
764
				/* process all gateways in this tier */
765
				foreach($tier as $member) {
766
					/* determine interface gateway */
767
					if (isset($gateways_arr[$member])) {
768
						$gateway = $gateways_arr[$member];
769
						$int = $gateway['interface'];
770
						$gatewayip = "";
771
						if(is_ipaddr($gateway['gateway'])) 
772
							$gatewayip = $gateway['gateway'];
773
						else if ($int <> "")
774
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
775
					
776
						if (($int <> "") && is_ipaddr($gatewayip)) {
777
							$groupmember = array();
778
							$groupmember['int']  = $int;
779
							$groupmember['gwip']  = $gatewayip;
780
							$groupmember['weight']  = isset($gateway['weight']) ? $gateway['weight'] : 1;
781
							if($gwvip_arr[$group['name']][$gwname] <> "")
782
								$groupmember['vip'] = $gwvip_arr[$group['name']][$gwname];
783
							$gateway_groups_array[$group['name']]['ipprotocol'] = $gateway['ipprotocol'];
784
							$gateway_groups_array[$group['name']][] = $groupmember;
785
						}
786
					}
787
				}
788
				/* we should have the 1st available tier now, exit stage left */
789
				break;
790
			}
791
		}
792
	}
793
	return ($gateway_groups_array);
794
}
795

    
796
/* Update DHCP WAN Interface ip address in gateway group item */
797
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
798
	global $config, $g;
799
	foreach($config['gateways']['gateway_item'] as & $gw) {	
800
		if($gw['interface'] == $interface) {
801
			$current_gw = get_interface_gateway($interface);
802
			if($gw['gateway'] <> $current_gw) {
803
				$gw['gateway'] = $current_gw;
804
				$changed = true;
805
			}
806
		}
807
	}
808
	if($changed && $current_gw)
809
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interfac, $current_gw));
810
}
811

    
812
function lookup_gateway_ip_by_name($name) {
813

    
814
	$gateways_arr = return_gateways_array();
815
        foreach ($gateways_arr as $gname => $gw) {
816
                if ($gw['name'] == $name || $gname == $name)
817
                        return $gw['gateway'];
818
        }
819

    
820
	return false;
821
}
822

    
823
function lookup_gateway_monitor_ip_by_name($name) {
824

    
825
        $gateways_arr = return_gateways_array();
826
	if (!empty($gateways_arr[$name])) {
827
		$gateway = $gateways_arr[$name];
828
		if(!is_ipaddr($gateway['monitor']))
829
			return $gateway['gateway'];
830

    
831
		return $gateway['monitor'];
832
        }
833

    
834
        return (false);
835
}
836

    
837
function lookup_gateway_interface_by_name($name) {
838

    
839
        $gateways_arr = return_gateways_array();
840
	if (!empty($gateways_arr[$name])) {
841
		$interfacegw = $gateway['interface'];
842
		return ($interfacegw);
843
        }
844

    
845
        return (false);
846
}
847

    
848
function get_interface_gateway($interface, &$dynamic = false) {
849
	global $config, $g;
850

    
851
	$gw = NULL;
852

    
853
	$gwcfg = $config['interfaces'][$interface];
854
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
855
		foreach($config['gateways']['gateway_item'] as $gateway) {
856
			if(($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
857
				$gw = $gateway['gateway'];
858
				break;
859
			}
860
		}
861
	}
862

    
863
	// for dynamic interfaces we handle them through the $interface_router file.
864
	if (!is_ipaddrv4($gw) && !is_ipaddrv4($gwcfg['ipaddr'])) {
865
		$realif = get_real_interface($interface);
866
		if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
867
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
868
			$dynamic = true;
869
		}
870
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw"))
871
			$dynamic = "default";
872
			
873
	}
874

    
875
	/* return gateway */
876
	return ($gw);
877
}
878

    
879
function get_interface_gateway_v6($interface, &$dynamic = false) {
880
	global $config, $g;
881

    
882
	$gw = NULL;
883
	$gwcfg = $config['interfaces'][$interface];
884
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
885
		foreach($config['gateways']['gateway_item'] as $gateway) {
886
			if(($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
887
				$gw = $gateway['gateway'];
888
				break;
889
			}
890
		}
891
	}
892

    
893
	// for dynamic interfaces we handle them through the $interface_router file.
894
	if (!is_ipaddrv6($gw) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
895
			$realif = get_real_interface($interface);
896
			if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
897
				$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
898
				$dynamic = true;
899
			}
900
			if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6"))
901
				$dynamic = "default";
902
			
903
	}
904
	/* return gateway */
905
	return ($gw);
906
}
907

    
908
/* Check a IP address against a gateway IP or name
909
 * to verify it's address family */
910
function validate_address_family($ipaddr, $gwname) {
911
	$v4ip = false;
912
	$v6ip = false;
913
	$v4gw = false;
914
	$v6gw = false;
915

    
916
	if(is_ipaddrv4($ipaddr))
917
		$v4ip = true;
918
	if(is_ipaddrv6($ipaddr))
919
		$v6ip = true;
920
	if(is_ipaddrv4($gwname))
921
		$v4gw = true;
922
	if(is_ipaddrv6($gwname))
923
		$v6gw = true;
924

    
925
	if($v4ip && $v4gw)
926
		return true;
927
	if($v6ip && $v6gw)
928
		return true;
929

    
930
	/* still no match, carry on, lookup gateways */
931
	if(is_ipaddrv4(lookup_gateway_ip_by_name($gwname)))
932
		$v4gw = true;
933
	if(is_ipaddrv6(lookup_gateway_ip_by_name($gwname)))
934
		$v6gw = true;
935

    
936
	$gw_array = return_gateways_array();
937
	if(is_array($gw_array[$gwname])) {
938
		switch($gw_array[$gwname]['ipprotocol']) {
939
			case "inet":
940
				$v4gw = true;
941
				break;
942
			case "inet6":
943
				$v6gw = true;
944
				break;
945
		}
946
	}
947

    
948
	if($v4ip && $v4gw)
949
		return true;
950
	if($v6ip && $v6gw)
951
		return true;
952
	
953
	return false;
954
}
955

    
956

    
957
?>
(25-25/65)