Project

General

Profile

Download (16.8 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/* $Id$ */
3
/*
4
  Copyright (C) 2008 Bill Marquette, Seth Mos
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

    
33
/* add static routes for monitor IP addresse
34
 * creates monitoring configuration file
35
 */
36
function setup_gateways_monitor() {
37
	global $config;
38
	global $g;
39
	$gateways_arr = return_gateways_array();
40
	if (!is_array($config['gateways']['gateway_item']))
41
		$config['gateways']['gateway_item'] = array();
42

    
43
	$a_gateway_item = &$config['gateways']['gateway_item'];
44

    
45
	if (is_array($config['gateways']['settings'])) {
46
		$a_settings = &$config['gateways']['settings'];
47
	} else {
48
		$a_settings['latencylow'] = "200";
49
		$a_settings['latencyhigh'] = "500";
50
		$a_settings['losslow'] = "10";
51
		$a_settings['losshigh'] = "20";
52
	}
53

    
54
	/* kill apinger process */
55
	if(is_process_running("apinger"))
56
		mwexec("/usr/bin/killall apinger", true);
57
	$fd = fopen("{$g['varetc_path']}/apinger.conf", "w");
58
	$apingerconfig = <<<EOD
59

    
60
# pfSense apinger configuration file. Automatically Generated!
61

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

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

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

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

    
75
status {
76
	## File where the status information whould be written to
77
	file "/tmp/apinger.status"
78
	## Interval between file updates
79
	## when 0 or not set, file is written only when SIGUSR1 is received
80
	interval 10s
81
}
82

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

    
88
## These parameters can be overriden in a specific alarm configuration
89
alarm default { 
90
	command on "/usr/bin/touch /tmp/filter_dirty"
91
	command off "/usr/bin/touch /tmp/filter_dirty"
92
	combine 10s
93
}
94

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

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

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

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

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

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

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

    
139
## Targets to probe
140
## Each one defined with:
141
## target <address> { <parameter>... }
142
## The parameters are those described above in the "target default" section
143
## plus the "description" parameter.
144
## the <address> should be IPv4 or IPv6 address (not hostname!)
145

    
146
EOD;
147

    
148
	/* add static routes for each gateway with their monitor IP */
149
	if(is_array($gateways_arr)) {
150
		$i = 2;
151
		foreach($gateways_arr as $name => $gateway) {
152
			/* for dynamic gateways without an IP address we subtitute a local one */
153
			if((is_numeric($gateway['attribute'])) && is_ipaddr($a_gateway_item[$gateway['attribute']]['monitor'])) {
154
				$gateway['monitor'] = $a_gateway_item[$gateway['attribute']]['monitor'];
155
			} else {
156
				if(($gateway['gateway'] == "dynamic") && ($gateway['monitor'])) {
157
					$gateway['monitor'] = "127.0.0.{$i}";
158
					$i++;
159
				}
160
				if(!is_ipaddr($gateway['monitor'])) {
161
					$gateway['monitor'] = $gateway['gateway'];
162
				}
163
			}
164
			$apingerconfig .= "target \"{$gateway['monitor']}\" {\n";
165
			$apingerconfig .= "	description \"{$gateway['name']}\"\n";
166
			$apingerconfig .= "	rrd file \"{$g['vardb_path']}/rrd/{$gateway['name']}-quality.rrd\"\n";
167
			$apingerconfig .= "}\n";
168
			$apingerconfig .= "\n";
169
			if($gateway['monitor'] == $gateway['gateway']) {
170
				/* if the gateway is the same as the monitor we do not add a
171
				 * route as this will break the routing table */
172
				continue;
173
			} else {
174
				if(($gateway['gateway'] != "dynamic") && (is_ipaddr($gateway['gateway']))) {
175
					mwexec("/sbin/route delete -host " . escapeshellarg($gateway['monitor']));
176
					mwexec("/sbin/route add -host " . escapeshellarg($gateway['monitor']) .
177
						" " . escapeshellarg($gateway['gateway']));
178
					log_error("Removing static route for monitor {$gateway['monitor']} and adding a new route through {$gateway['gateway']}");
179
				}
180
			}
181
		}
182
	}
183
	fwrite($fd, $apingerconfig);
184
	fclose($fd);
185

    
186
	if(!is_process_running("apinger")) {
187
		if (is_dir("{$g['tmp_path']}"))
188
			chmod("{$g['tmp_path']}", 01777);
189
		if (is_dir("{$g['vardb_path']}/rrd"))
190
			chown("{$g['vardb_path']}/rrd", "nobody");
191
		/* start a new apinger process */
192
		mwexec_bg("/usr/local/sbin/apinger -c {$g['varetc_path']}/apinger.conf");
193
	}
194
	return 0;
195
}
196

    
197
/* return the status of the apinger targets as a array */
198
function return_gateways_status() {
199
	global $config;
200
	global $g;
201
	$gateways_arr = return_gateways_array();
202

    
203
	$apingerstatus = array();
204
	if(is_readable("{$g['tmp_path']}/apinger.status")) {
205
		$apingerstatus = file("{$g['tmp_path']}/apinger.status");
206
	}
207

    
208
	$status = array();
209
	$i = 2;
210
	/* assign a dummy IP address for dynamic interfaces in case we need it */
211
	$monitor = array();
212
	foreach($gateways_arr as $name => $gateway) {
213
		if($gateway['monitor'] == "dynamic") {
214
			$gateway['monitor'] = "127.0.0.{$i}";
215
			$i++;
216
		}
217
		$status[$gateway['monitor']]['monitor'] = $gateway['monitor'];
218
		$status[$gateway['monitor']]['interface'] = $gateway['interface'];
219
		$status[$gateway['monitor']]['gateway'] = $gateway['gateway'];
220
		$status[$gateway['monitor']]['name'] = $gateway['name'];
221
		$status[$gateway['monitor']]['status'] = "down";
222

    
223
	}
224
	foreach($apingerstatus as $line) {
225
		$fields = explode(":", $line);
226
		switch($fields[0]) {
227
			case "Target":
228
				$target = trim($fields[1]);
229
				break;
230
			case "Description":
231
				if($target)
232
		 			$status[$target]['name'] = trim($fields[1]);
233
				break;
234
			case "Last reply received":
235
				if($target)
236
					$status[$target]['lastcheck'] = trim($fields[1]) .":". trim($fields[2]) .":". trim($fields[3]);
237
				break;
238
			case "Average delay":
239
				if($target)
240
					$status[$target]['delay'] = trim($fields[1]);
241
				break;
242
			case "Average packet loss":
243
				if($target)
244
					$status[$target]['loss'] = trim($fields[1]);
245
				break;
246
			case "Active alarms":
247
				if($target)
248
					$status[$target]['status'] = trim($fields[1]);
249
				break;
250
		}
251
	}
252
	return($status);
253
}
254

    
255
/* Return all configured gateways on the system */
256
function return_gateways_array($disabled = false) {
257
	global $config;
258

    
259
	$gateways_arr = array();
260

    
261
	/* Loop through all interfaces with a gateway and add it to a array */
262
	if ($disabled == false) {
263
		$iflist = get_configured_interface_with_descr();
264
	} else {
265
		$iflist = get_configured_interface_with_descr(false, true);
266
	}
267

    
268
	$i = 0;
269
	/* tack on all the hard defined gateways as well */
270
	if(is_array($config['gateways']['gateway_item'])) {
271
		foreach($config['gateways']['gateway_item'] as $gateway) {
272
			if($gateway['gateway'] == "dynamic") {
273
				$gateway['gateway'] = get_interface_gateway($gateway['interface']);
274
				/* no IP address found, set to dynamic */
275
				if(! is_ipaddr($gateway['gateway'])) {
276
					$gateway['gateway'] = "dynamic";
277
				}
278
				$gateway['dynamic'] = true;
279
			}
280
			if($gateway['monitor'] == "") {
281
				$gateway['monitor'] = $gateway['gateway'];
282
			}
283
			/* include the gateway index as the attribute */
284
			$gateway['friendlyiface'] = $gateway['interface'];
285
			$gateway['interface'] = convert_friendly_interface_to_real_interface_name($gateway['interface']);
286
			$gateway['attribute'] = "$i";
287

    
288
			$gateways_arr[$gateway['name']] = $gateway;
289
			$i++;
290
		}
291
	} 
292

    
293
	foreach($iflist as $ifname => $friendly ) {
294
		if(! interface_has_gateway($ifname)) {
295
			continue;
296
		}
297
		$gateway = array();
298
		$gateway['dynamic'] = false;
299
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
300
		$gateway['interface'] = get_real_interface($ifname);
301
		$gateway['friendlyiface'] = $ifname;
302
		$gateway['name'] = "{$friendly}";
303
		$gateway['attribute'] = "system";
304
	
305
		/* Loopback dummy for dynamic interfaces without a IP */
306
		if(!is_ipaddr(trim($gateway['gateway'])) && $gateway['dynamic'] == true) {
307
			 $gateway['gateway'] = "dynamic";
308
		}
309

    
310
		/* automatically skip known static and dynamic gateways we have a array entry for */
311
		foreach($gateways_arr as $gateway_item) {
312
			if ($ifname == $gateway_item['friendlyiface'] || $friendly == $gateway_item['name']) {
313
				if ($gateway_item['gateway'] == $gateway['gateway'])
314
					continue 2;
315
				if ($gateway_item['gateway'] == "dynamic")
316
					continue 2;
317
			}
318
		}
319

    
320
		/* retrieve a proper monitor IP? */
321
		$interface = $config['interfaces'][$ifname];
322
		if(is_ipaddr($interface['monitorip'])) {
323
			$gateway['monitor'] = $interface['monitorip'];
324
		} else {
325
			$gateway['monitor'] = $gateway['gateway'];
326
		}
327
		$gateway['descr'] = "Interface $ifname Dynamic Gateway";
328
		$gateways_arr[$ifname] = $gateway;
329
		$i++;
330
	}
331

    
332
	return($gateways_arr);
333
}
334

    
335

    
336
/* return a array with all gateway groups with name as key
337
 * All gateway groups will be processed before returning the array.
338
*/
339
function return_gateway_groups_array() {
340
	global $config, $g;
341

    
342
	/* fetch the current gateways status */
343
	$gateways_status = return_gateways_status();
344
	$gateways_arr = return_gateways_array();
345
	$gateway_groups_array = array();
346

    
347
	if (is_array($config['gateways']['gateway_group'])) {
348
		foreach($config['gateways']['gateway_group'] as $group) {
349
			/* create array with group gateways members seperated by tier */
350
			$tiers = array();
351
			foreach($group['item'] as $item) {
352
				$itemsplit = explode("|", $item);
353
				$tier = $itemsplit[1];
354
				$gwname = $itemsplit[0];
355
				/* check if the gateway is available before adding it to the array */
356
				foreach($gateways_status as $status) {
357
					if(($status['name'] != $gwname)) {
358
						continue;
359
					}
360
					if (stristr($status['status'], "down")) {
361
						$msg = "MONITOR: $gwname has high latency, removing from routing group";
362
						log_error($msg);
363
						notify_via_growl($msg);
364
					} elseif (stristr($status['status'], "loss")) {
365
						if (strstr($group['trigger'], "loss")) {
366
							/* packet loss */
367
							$msg = "MONITOR: $gwname has packet loss, removing from routing group";
368
							log_error($msg);
369
							notify_via_growl($msg);
370
						} else {
371
							$tiers[$tier][] = $gwname;
372
						}
373
					} elseif (stristr($status['status'], $delay)) {
374
						if (strstr($group['trigger'] , "latency")) {
375
							/* high latency */
376
							$msg = "MONITOR: $gwname has high latency, removing from routing group";
377
							log_error($msg);
378
							notify_via_growl($msg);
379
						} else {
380
							$tiers[$tier][] = $gwname;
381
						}
382
					} elseif (stristr($status['status'], "none")) {
383
						/* Online add member */
384
						$tiers[$tier][] = $gwname;
385
					}
386
				}
387
			}
388
			$tiers_count = count($tiers);
389
			if($tiers_count == 0) {
390
				/* Oh dear, we have no members! Engage Plan B */
391
				$msg = "All gateways are unavailable, proceeding with configured XML settings!";
392
				log_error($msg);
393
				notify_via_growl($msg);
394
				foreach($group['item'] as $item) {
395
					foreach($group['item'] as $item) {
396
						$itemsplit = explode("|", $item);
397
						$tier = $itemsplit[1];
398
						$gwname = $itemsplit[0];
399
						$tiers[$tier][] = $gwname;
400
					}
401
				}
402
			}
403
			/* sort the tiers array by the tier key */
404
			ksort($tiers);
405
			/* we do not really foreach the tiers as we stop after the first tier */
406
			foreach($tiers as $tiernr => $tier) {
407
				/* process all gateways in this tier */
408
				foreach($tier as $tiernr => $member) {
409
					/* determine interface gateway */
410
					if (isset($gateways_arr[$member])) {
411
						$gateway = $gateways_arr[$member];
412
						$int = $gateway['interface'];
413
						$gatewayip = "";
414
						if(is_ipaddr($gateway['gateway'])) 
415
							$gatewayip = $gateway['gateway'];
416
						else if ($int <> "")
417
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
418
					}
419
					if (($int <> "") && is_ipaddr($gatewayip)) {
420
						$gateway_groups_array[$group['name']][$tiernr]['int']  = "$int";
421
						$gateway_groups_array[$group['name']][$tiernr]['gwip']  = "$gatewayip";
422
						$gateway_groups_array[$group['name']][$tiernr]['weight']  = isset($gateway['weight']) ? $gateway['weight'] : 1;
423
					}
424
				}
425
				/* we should have the 1st available tier now, exit stage left */
426
				break;
427
			}
428
		}
429
	}
430
	return($gateway_groups_array);
431
}
432

    
433
/* Update DHCP WAN Interface ip address in gateway group item */
434
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
435
	global $config, $g;
436
	foreach($config['gateways']['gateway_item'] as & $gw) {	
437
		if($gw['interface'] == $interface) {
438
			$current_gw = get_interface_gateway($interface);
439
			if($gw['gateway'] <> $current_gw) {
440
				$gw['gateway'] = $current_gw;
441
				$changed = true;
442
			}
443
		}
444
	}
445
	if($changed && $current_gw)
446
		write_config("Updating gateway group gateway for $interface - new gateway is $current_gw");
447
}
448

    
449
function lookup_gateway_ip_by_name($name) {
450
        global $config;
451
        if(is_array($config['gateways']['gateway_item'])) {
452
                foreach($config['gateways']['gateway_item'] as $gateway) {
453
                        if($gateway['name'] == $name) {
454
                                $gatewayip = $gateway['gateway'];
455
                                //$interfacegw = $gateway['interface'];
456
                                return($gatewayip);
457
                        }
458
                }
459
        } else {
460
                return(false);
461
        }
462
}
463

    
464
function lookup_gateway_monitor_ip_by_name($name) {
465
        global $config;
466
        $gateways_arr = return_gateways_array();
467

    
468
	$i = 2;
469
        foreach($gateways_arr as $gateway) {
470
		if($gateway['gateway'] == "dynamic") {
471
			$gateway['monitor'] = "127.0.0.{$i}";
472
			$i++;
473
		}
474
                if($gateway['name'] == "$name") {
475
                        $monitorip = $gateway['monitor'];
476
                        if($monitorip == "")
477
                                $monitorip = $gateway['gateway'];
478

    
479
                        return($monitorip);
480
                }
481
        }
482
        return(false);
483
}
484

    
485
function lookup_gateway_interface_by_name($name) {
486
        global $config;
487
        $gateways_arr = return_gateways_array();
488

    
489
        foreach($gateways_arr as $gateway) {
490
                if($gateway['name'] == "$name") {
491
                        $gatewayip = $gateway['gateway'];
492
                        $interfacegw = $gateway['interface'];
493
                        return($interfacegw);
494
                }
495
        }
496
        return(false);
497
}
498

    
499
function get_interface_gateway($interface, &$dynamic = false) {
500
        global $config, $g;
501

    
502
        $gw = NULL;
503

    
504
        $gwcfg = $config['interfaces'][$interface];
505
        if (is_ipaddr($gwcfg['gateway']))
506
                $gw = $gwcfg['gateway'];
507
        else if (!empty($gwcfg['gateway']))
508
                $gw = lookup_gateway_ip_by_name($gwcfg['gateway']);
509

    
510
        // for dynamic interfaces we handle them through the $interface_router file.
511
        if (!is_ipaddr($gw) && !is_ipaddr($gwcfg['ipaddr'])) {
512
                $realif = get_real_interface($interface);
513
                if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
514
                        $gw = file_get_contents("{$g['tmp_path']}/{$realif}_router");
515
                        $gw = rtrim($gw);
516
			$dynamic = true;
517
                }
518
        }
519

    
520
        /* return gateway */
521
        return $gw;
522
}
523

    
524
?>
(20-20/50)