Project

General

Profile

Download (17.6 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

    
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
	$gateways_status = return_gateways_status();
41
	if (!is_array($config['gateways']['gateway_item']))
42
		$config['gateways']['gateway_item'] = array();
43

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

    
46
	$a_settings = array();
47
	$a_settings['latencylow'] = "200";
48
	$a_settings['latencyhigh'] = "500";
49
	$a_settings['losslow'] = "10";
50
	$a_settings['losshigh'] = "20";
51

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

    
55
# pfSense apinger configuration file. Automatically Generated!
56

    
57
## User and group the pinger should run as
58
user "root"
59
group "wheel"
60

    
61
## Mailer to use (default: "/usr/lib/sendmail -t")
62
#mailer "/var/qmail/bin/qmail-inject" 
63

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

    
67
## Format of timestamp (%s macro) (default: "%b %d %H:%M:%S")
68
#timestamp_format "%Y%m%d%H%M%S"
69

    
70
status {
71
	## File where the status information whould be written to
72
	file "/tmp/apinger.status"
73
	## Interval between file updates
74
	## when 0 or not set, file is written only when SIGUSR1 is received
75
	interval 10s
76
}
77

    
78
########################################
79
# RRDTool status gathering configuration
80
# Interval between RRD updates
81
rrd interval 60s;
82

    
83
## These parameters can be overriden in a specific alarm configuration
84
alarm default { 
85
	command on "/usr/bin/touch /tmp/filter_dirty"
86
	command off "/usr/bin/touch /tmp/filter_dirty"
87
	combine 10s
88
}
89

    
90
## "Down" alarm definition. 
91
## This alarm will be fired when target doesn't respond for 30 seconds.
92
alarm down "down" {
93
	time 10s
94
}
95

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

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

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

    
123
	## The delay (in samples) after which loss is computed
124
	## without this delays larger than interval would be treated as loss
125
	avg_loss_delay_samples 20
126

    
127
	## Names of the alarms that may be generated for the target
128
	alarms "down","delay","loss"
129

    
130
	## Location of the RRD
131
	#rrd file "{$g['vardb_path']}/rrd/apinger-%t.rrd"
132
}
133

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

    
141
EOD;
142

    
143
	/* add static routes for each gateway with their monitor IP */
144
	if(is_array($gateways_arr)) {
145
		$i = 2;
146
		foreach($gateways_arr as $name => $gateway) {
147
			$gwref = $a_gateway_item[$gateway['attribute']];
148
			/* for dynamic gateways without an IP address we subtitute a local one */
149
			if(is_ipaddr($gwref['monitor'])) {
150
				$gateway['monitor'] = $gwref['monitor'];
151
			} else {
152
				if ($gateway['gateway'] == "dynamic") {
153
					$gateway['monitor'] = "127.0.0.{$i}";
154
					$i++;
155
				}
156
				if (!is_ipaddr($gateway['monitor']))
157
					$gateway['monitor'] = $gateway['gateway'];
158
			}
159

    
160
			if (!is_ipaddr($gateway['monitor']))
161
				continue;
162

    
163
			if($gateway['monitor'] == "127.0.0.{$i}") {
164
				$gwifip = "127.0.0.1";
165
			} else {
166
				$gwifip = find_interface_ip($gateway['interface']);
167
			}
168
			if (!is_ipaddr($gwifip))
169
				continue; //Skip this target
170

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

    
221
			$apingercfg .= "	rrd file \"{$g['vardb_path']}/rrd/{$gateway['name']}-quality.rrd\"\n";
222
			$apingercfg .= "}\n";
223
			$apingercfg .= "\n";
224
			if($gateway['monitor'] == $gateway['gateway']) {
225
				/* if the gateway is the same as the monitor we do not add a
226
				 * route as this will break the routing table */
227
				continue;
228
			} else {
229
				if ($gateway['gateway'] != "dynamic" && is_ipaddr($gateway['gateway'])) {
230
					mwexec("/sbin/route delete -host " . escapeshellarg($gateway['monitor']));
231
					mwexec("/sbin/route add -host " . escapeshellarg($gateway['monitor']) .
232
						" " . escapeshellarg($gateway['gateway']));
233
					log_error(sprintf(gettext("Removing static route for monitor %s and adding a new route through %s"), $gateway['monitor'], $gateway['gateway']));
234
				}
235
			}
236
		}
237
		$apingerconfig .= $alarmscfg;
238
		$apingerconfig .= $apingercfg;
239
	}
240
	fwrite($fd, $apingerconfig);
241
	fclose($fd);
242

    
243
	killbypid("{$g['varrun_path']}/apinger.pid");
244
	if (is_dir("{$g['tmp_path']}"))
245
		chmod("{$g['tmp_path']}", 01777);
246
	if (!is_dir("{$g['vardb_path']}/rrd")) {
247
		mkdir("{$g['vardb_path']}/rrd", 0775);
248
	}
249
	if (is_dir("{$g['vardb_path']}/rrd"))
250
		chown("{$g['vardb_path']}/rrd", "nobody");
251
	/* start a new apinger process */
252
	mwexec_bg("/usr/local/sbin/apinger -c {$g['varetc_path']}/apinger.conf");
253

    
254
	return 0;
255
}
256

    
257
/* return the status of the apinger targets as a array */
258
function return_gateways_status() {
259
	global $config, $g;
260

    
261
	$apingerstatus = array();
262
	if (file_exists("{$g['tmp_path']}/apinger.status")) {
263
		$apingerstatus = file("{$g['tmp_path']}/apinger.status");
264
	}
265

    
266
	$status = array();
267
	foreach($apingerstatus as $line) {
268
		$info = explode("|", $line);
269
		$target = $info[0];
270
		$status[$target]['srcip'] = $info[1];
271
		$status[$target]['name'] = $info[2];
272
		$status[$target]['lastcheck'] = $info[5] ? date('r', $info[5]) : date('r');
273
		$status[$target]['delay'] = empty($info[6]) ? 0 : $info[6];
274
		$status[$target]['loss'] = empty($info[7]) ? "0.0%" : $info[7] . "";
275
		$status[$target]['status'] = trim($info[8]);
276
	}
277
	return($status);
278
}
279

    
280
/* Return all configured gateways on the system */
281
function return_gateways_array($disabled = false) {
282
	global $config;
283

    
284
	$gateways_arr = array();
285

    
286
	/* Loop through all interfaces with a gateway and add it to a array */
287
	if ($disabled == false) {
288
		$iflist = get_configured_interface_with_descr();
289
	} else {
290
		$iflist = get_configured_interface_with_descr(false, true);
291
	}
292

    
293
	$i = 0;
294
	/* tack on all the hard defined gateways as well */
295
	if(is_array($config['gateways']['gateway_item'])) {
296
		foreach($config['gateways']['gateway_item'] as $gateway) {
297
			if($gateway['gateway'] == "dynamic") {
298
				$gateway['gateway'] = get_interface_gateway($gateway['interface']);
299
				/* no IP address found, set to dynamic */
300
				if(! is_ipaddr($gateway['gateway'])) {
301
					$gateway['gateway'] = "dynamic";
302
				}
303
				$gateway['dynamic'] = true;
304
			}
305
			if($gateway['monitor'] == "") {
306
				$gateway['monitor'] = $gateway['gateway'];
307
			}
308
			/* include the gateway index as the attribute */
309
			$gateway['friendlyiface'] = $gateway['interface'];
310
			$gateway['interface'] = convert_friendly_interface_to_real_interface_name($gateway['interface']);
311
			$gateway['attribute'] = "$i";
312

    
313
			$gateways_arr[$gateway['name']] = $gateway;
314
			$i++;
315
		}
316
	} 
317

    
318
	foreach($iflist as $ifname => $friendly ) {
319
		if(! interface_has_gateway($ifname)) {
320
			continue;
321
		}
322
		$gateway = array();
323
		$gateway['dynamic'] = false;
324
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
325
		$gateway['interface'] = get_real_interface($ifname);
326
		$gateway['friendlyiface'] = $ifname;
327
		$gateway['name'] = "{$friendly}";
328
		$gateway['attribute'] = "system";
329
	
330
		/* Loopback dummy for dynamic interfaces without a IP */
331
		if(!is_ipaddr(trim($gateway['gateway'])) && $gateway['dynamic'] == true) {
332
			 $gateway['gateway'] = "dynamic";
333
		}
334

    
335
		/* automatically skip known static and dynamic gateways we have a array entry for */
336
		foreach($gateways_arr as $gateway_item) {
337
			if ($ifname == $gateway_item['friendlyiface'] || $friendly == $gateway_item['name']) {
338
				if ($gateway_item['gateway'] == $gateway['gateway'])
339
					continue 2;
340
				if ($gateway_item['gateway'] == "dynamic")
341
					continue 2;
342
			}
343
		}
344

    
345
		/* retrieve a proper monitor IP? */
346
		$interface = $config['interfaces'][$ifname];
347
		if(is_ipaddr($interface['monitorip'])) {
348
			$gateway['monitor'] = $interface['monitorip'];
349
		} else {
350
			$gateway['monitor'] = $gateway['gateway'];
351
		}
352
		$gateway['descr'] = "Interface $ifname Dynamic Gateway";
353
		$gateways_arr[$ifname] = $gateway;
354
		$i++;
355
	}
356

    
357
	return($gateways_arr);
358
}
359

    
360

    
361
/* return a array with all gateway groups with name as key
362
 * All gateway groups will be processed before returning the array.
363
*/
364
function return_gateway_groups_array() {
365
	global $config, $g;
366

    
367
	/* fetch the current gateways status */
368
	$gateways_status = return_gateways_status();
369
	$gateways_arr = return_gateways_array();
370
	$gateway_groups_array = array();
371

    
372
	if (is_array($config['gateways']['gateway_group'])) {
373
		foreach($config['gateways']['gateway_group'] as $group) {
374
			/* create array with group gateways members seperated by tier */
375
			$tiers = array();
376
			foreach($group['item'] as $item) {
377
				$itemsplit = explode("|", $item);
378
				$tier = $itemsplit[1];
379
				$gwname = $itemsplit[0];
380
				/* check if the gateway is available before adding it to the array */
381
				foreach($gateways_status as $status) {
382
					if ($status['name'] != $gwname) {
383
						continue;
384
					}
385
					if (stristr($status['status'], "down")) {
386
						$msg = sprintf(gettext("MONITOR: %s has high latency, removing from routing group"), $gwname);
387
						log_error($msg);
388
						notify_via_growl($msg);
389
					} elseif (stristr($status['status'], "loss")) {
390
						if (strstr($group['trigger'], "loss")) {
391
							/* packet loss */
392
							$msg = sprintf(gettext("MONITOR: %s has packet loss, removing from routing group"), $gwname);
393
							log_error($msg);
394
							notify_via_growl($msg);
395
						} else {
396
							$tiers[$tier][] = $gwname;
397
						}
398
					} elseif (stristr($status['status'], "delay")) {
399
						if (strstr($group['trigger'] , "latency")) {
400
							/* high latency */
401
							$msg = sprintf(gettext("MONITOR: %s has high latency, removing from routing group"), $gwname);
402
							$msg = "MONITOR: $gwname has high latency, removing from routing group";
403
							log_error($msg);
404
							notify_via_growl($msg);
405
						} else {
406
							$tiers[$tier][] = $gwname;
407
						}
408
					} elseif ($status['status'] == "none") {
409
						/* Online add member */
410
						$tiers[$tier][] = $gwname;
411
					}
412
				}
413
			}
414
			$tiers_count = count($tiers);
415
			if($tiers_count == 0) {
416
				/* Oh dear, we have no members! Engage Plan B */
417
				$msg = gettext("All gateways are unavailable, proceeding with configured XML settings!");
418
				log_error($msg);
419
				notify_via_growl($msg);
420
				foreach($group['item'] as $item) {
421
					$itemsplit = explode("|", $item);
422
					$tier = $itemsplit[1];
423
					$gwname = $itemsplit[0];
424
					$tiers[$tier][] = $gwname;
425
				}
426
			}
427
			/* sort the tiers array by the tier key */
428
			ksort($tiers);
429
			/* we do not really foreach the tiers as we stop after the first tier */
430
			foreach($tiers as $tier) {
431
				/* process all gateways in this tier */
432
				foreach($tier as $member) {
433
					/* determine interface gateway */
434
					if (isset($gateways_arr[$member])) {
435
						$gateway = $gateways_arr[$member];
436
						$int = $gateway['interface'];
437
						$gatewayip = "";
438
						if(is_ipaddr($gateway['gateway'])) 
439
							$gatewayip = $gateway['gateway'];
440
						else if ($int <> "")
441
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
442
					}
443
					if (($int <> "") && is_ipaddr($gatewayip)) {
444
						$groupmember = array();
445
						$groupmember['int']  = "$int";
446
						$groupmember['gwip']  = "$gatewayip";
447
						$groupmember['weight']  = isset($gateway['weight']) ? $gateway['weight'] : 1;
448
						$gateway_groups_array[$group['name']][] = $groupmember;
449
					}
450
				}
451
				/* we should have the 1st available tier now, exit stage left */
452
				break;
453
			}
454
		}
455
	}
456
	return ($gateway_groups_array);
457
}
458

    
459
/* Update DHCP WAN Interface ip address in gateway group item */
460
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
461
	global $config, $g;
462
	foreach($config['gateways']['gateway_item'] as & $gw) {	
463
		if($gw['interface'] == $interface) {
464
			$current_gw = get_interface_gateway($interface);
465
			if($gw['gateway'] <> $current_gw) {
466
				$gw['gateway'] = $current_gw;
467
				$changed = true;
468
			}
469
		}
470
	}
471
	if($changed && $current_gw)
472
		write_config(sprintf(gettext("Updating gateway group gateway for %s - new gateway is %s"), $interfac, $current_gw));
473
}
474

    
475
function lookup_gateway_ip_by_name($name) {
476

    
477
	$gateways_arr = return_gateways_array();
478
        foreach ($gateways_arr as $gw) {
479
                if ($gw['name'] == $name)
480
                        return $gw['gateway'];
481
        }
482

    
483
	return false;
484
}
485

    
486
function lookup_gateway_monitor_ip_by_name($name) {
487

    
488
        $gateways_arr = return_gateways_array();
489
	if (!empty($gateways_arr[$name])) {
490
		$gateway = $gateways_arr[$name];
491
		if ($gateway['gateway'] == "dynamic")
492
			$gateway['monitor'] = "127.0.0.2";
493

    
494
		$monitorip = $gateway['monitor'];
495
		if(!is_ipaddr($monitorip))
496
			$monitorip = $gateway['gateway'];
497

    
498
		return ($monitorip);
499
        }
500

    
501
        return (false);
502
}
503

    
504
function lookup_gateway_interface_by_name($name) {
505

    
506
        $gateways_arr = return_gateways_array();
507
	if (!empty($gateways_arr[$name])) {
508
		//$gatewayip = $gateway['gateway'];
509
		$interfacegw = $gateway['interface'];
510
		return ($interfacegw);
511
        }
512

    
513
        return (false);
514
}
515

    
516
function get_interface_gateway($interface, &$dynamic = false) {
517
        global $config, $g;
518

    
519
        $gw = NULL;
520

    
521
        $gwcfg = $config['interfaces'][$interface];
522
        if (is_ipaddr($gwcfg['gateway']))
523
                $gw = $gwcfg['gateway'];
524
        else if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
525
               	foreach($config['gateways']['gateway_item'] as $gateway) {
526
                        if ($gateway['name'] == $gwcfg['gateway']) {
527
                                $gw = $gateway['gateway'];
528
				break;
529
			}
530
                }
531
	}
532

    
533
        // for dynamic interfaces we handle them through the $interface_router file.
534
        if (!is_ipaddr($gw) && !is_ipaddr($gwcfg['ipaddr'])) {
535
                $realif = get_real_interface($interface);
536
                if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
537
                        $gw = file_get_contents("{$g['tmp_path']}/{$realif}_router");
538
                        $gw = rtrim($gw);
539
			$dynamic = true;
540
                }
541
        }
542

    
543
        /* return gateway */
544
        return ($gw);
545
}
546

    
547
?>
(21-21/53)