Project

General

Profile

Download (61.6 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/*
3
 * gwlb.inc
4
 *
5
 * part of pfSense (https://www.pfsense.org)
6
 * Copyright (c) 2008 Bill Marquette, Seth Mos
7
 * Copyright (c) 2008-2018 Rubicon Communications, LLC (Netgate)
8
 * All rights reserved.
9
 *
10
 * Licensed under the Apache License, Version 2.0 (the "License");
11
 * you may not use this file except in compliance with the License.
12
 * You may obtain a copy of the License at
13
 *
14
 * http://www.apache.org/licenses/LICENSE-2.0
15
 *
16
 * Unless required by applicable law or agreed to in writing, software
17
 * distributed under the License is distributed on an "AS IS" BASIS,
18
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19
 * See the License for the specific language governing permissions and
20
 * limitations under the License.
21
 */
22

    
23
require_once("config.inc");
24
require_once("rrd.inc");
25

    
26
/* Returns an array of default values used for dpinger */
27
function return_dpinger_defaults() {
28
	return array(
29
		"latencylow" => "200",
30
		"latencyhigh" => "500",
31
		"losslow" => "10",
32
		"losshigh" => "20",
33
		"interval" => "500",
34
		"loss_interval" => "2000",
35
		"time_period" => "60000",
36
		"alert_interval" => "1000",
37
		"data_payload" => "0");
38
}
39

    
40
function running_dpinger_processes() {
41
	global $g;
42

    
43
	$pidfiles = glob("{$g['varrun_path']}/dpinger_*.pid");
44

    
45
	$result = array();
46
	if ($pidfiles === FALSE) {
47
		return $result;
48
	}
49

    
50
	foreach ($pidfiles as $pidfile) {
51
		if (preg_match('/^dpinger_(.+)~([^~]+)~([^~]+)\.pid$/',
52
		    basename($pidfile), $matches)) {
53
			$socket_file = preg_replace('/\.pid$/', '.sock',
54
			    $pidfile);
55
			$result[$matches[1]] = array(
56
			    'srcip'    => $matches[2],
57
			    'targetip' => $matches[3],
58
			    'pidfile'  => $pidfile,
59
			    'socket'   => $socket_file
60
			);
61
			unset($gwinfo);
62
		}
63
	}
64

    
65
	return $result;
66
}
67

    
68
/*
69
 * Stop one or more dpinger process
70
 * default parameter $gwname is '*' that will kill all running sessions
71
 * If a gateway name is passed, only this one will be killed
72
 */
73
function stop_dpinger($gwname = '') {
74
	global $g;
75

    
76
	$running_processes = running_dpinger_processes();
77

    
78
	foreach ($running_processes as $running_gwname => $process) {
79
		if ($gwname != '' && $running_gwname != $gwname) {
80
			continue;
81
		}
82

    
83
		if (isvalidpid($process['pidfile'])) {
84
			killbypid($process['pidfile']);
85
		} else {
86
			@unlink($process['pidfile']);
87
		}
88
	}
89
}
90

    
91
function start_dpinger($gateway) {
92
	global $g;
93

    
94
	if (!isset($gateway['gwifip'])) {
95
		return (false);
96
	}
97

    
98
	$dpinger_defaults = return_dpinger_defaults();
99

    
100
	$prefix = "{$g['varrun_path']}/dpinger_{$gateway['name']}~" .
101
	    "{$gateway['gwifip']}~{$gateway['monitor']}";
102
	# dpinger socket path should not be longer then uaddr.sun_path
103
	if (strlen($prefix) > 95) {
104
		$prefix = "{$g['varrun_path']}/dpinger_{$gateway['name']}~" .
105
		    substr(md5($gateway['gwifip']),0,8) . "~" .
106
		    $gateway['monitor'];
107
	}
108
	$pidfile = $prefix . ".pid";
109
	$socket = $prefix . ".sock";
110
	$alarm_cmd = "{$g['etc_path']}/rc.gateway_alarm";
111

    
112
	$params  = "-S ";			/* Log warnings via syslog */
113
	$params .= "-r 0 ";			/* Disable unused reporting thread */
114
	$params .= "-i {$gateway['name']} ";	/* Identifier */
115
	$params .= "-B {$gateway['gwifip']} ";	/* Bind src address */
116
	$params .= "-p {$pidfile} ";		/* PID filename */
117
	$params .= "-u {$socket} ";		/* Status Socket */
118
	if (!$gateway['action_disable']) {
119
		$params .= "-C \"{$alarm_cmd}\" ";	/* Command to run on alarm */
120
	}
121

    
122
	$params .= "-d " .
123
	    (isset($gateway['data_payload']) && is_numeric($gateway['data_payload'])
124
	    ? $gateway['data_payload']
125
	    : $dpinger_defaults['data_payload']
126
	    ) . " ";
127

    
128
	$params .= "-s " .
129
	    (isset($gateway['interval']) && is_numeric($gateway['interval'])
130
	    ? $gateway['interval']
131
	    : $dpinger_defaults['interval']
132
	    ) . " ";
133

    
134
	$params .= "-l " .
135
	    (isset($gateway['loss_interval']) && is_numeric($gateway['loss_interval'])
136
	    ?  $gateway['loss_interval']
137
	    : $dpinger_defaults['loss_interval']
138
	    ) . " ";
139

    
140
	$params .= "-t " .
141
	    (isset($gateway['time_period']) && is_numeric($gateway['time_period'])
142
	    ?  $gateway['time_period']
143
	    : $dpinger_defaults['time_period']
144
	    ) . " ";
145

    
146
	$params .= "-A " .
147
	    (isset($gateway['alert_interval']) && is_numeric($gateway['alert_interval'])
148
	    ?  $gateway['alert_interval']
149
	    : $dpinger_defaults['alert_interval']
150
	    ) . " ";
151

    
152
	$params .= "-D " .
153
	    (isset($gateway['latencyhigh']) && is_numeric($gateway['latencyhigh'])
154
	    ?  $gateway['latencyhigh']
155
	    : $dpinger_defaults['latencyhigh']
156
	    ) . " ";
157

    
158
	$params .= "-L " .
159
	    (isset($gateway['losshigh']) && is_numeric($gateway['losshigh'])
160
	    ?  $gateway['losshigh']
161
	    : $dpinger_defaults['losshigh']
162
	    ) . " ";
163

    
164
	/* Make sure we don't end up with 2 process for the same GW */
165
	stop_dpinger($gateway['name']);
166

    
167
	/* Do not try to bind IPv6 where interface is in tentative state */
168
	if (is_ipaddrv6($gateway['gwifip'])) {
169
		$err = interface_wait_tentative(get_real_interface(
170
		    $gateway['interface']));
171
		if ($err == false) {
172
			log_error(gettext("Timeout waiting for IPv6 address in tentative state.  dpinger will not run."));
173
			return (false);
174
		}
175
	}
176

    
177
	/* Redirect stdout to /dev/null to avoid exec() to wait for dpinger */
178
	return mwexec("/usr/local/bin/dpinger {$params} {$gateway['monitor']} >/dev/null");
179
}
180

    
181
/*
182
 * Starts dpinger processes and adds appropriate static routes for monitor IPs
183
 */
184
function setup_gateways_monitor() {
185
	global $config, $g;
186

    
187
	$gateways_arr = return_gateways_array();
188
	if (!is_array($gateways_arr)) {
189
		log_error(gettext("No gateways to monitor. dpinger will not run."));
190
		stop_dpinger();
191
		return;
192
	}
193

    
194
	$monitor_ips = array();
195
	foreach ($gateways_arr as $gwname => $gateway) {
196
		/* Do not monitor if such was requested */
197
		if (isset($gateway['monitor_disable'])) {
198
			continue;
199
		}
200
		if (empty($gateway['monitor']) || !is_ipaddr($gateway['monitor'])) {
201
			if (is_ipaddr($gateway['gateway'])) {
202
				$gateways_arr[$gwname]['monitor'] = $gateway['gateway'];
203
			} else { /* No chance to get an ip to monitor skip target. */
204
				continue;
205
			}
206
		}
207

    
208
		/* if the monitor address is already used before, skip */
209
		if (in_array($gateway['monitor'], $monitor_ips)) {
210
			continue;
211
		}
212

    
213
		/* Interface ip is needed since dpinger will bind a socket to it.
214
		 * However the config GUI should already have checked this and when
215
		 * PPPoE is used the IP address is set to "dynamic". So using is_ipaddrv4
216
		 * or is_ipaddrv6 to identify packet type would be wrong, especially as
217
		 * further checks (that can cope with the "dynamic" case) are present inside
218
		 * the if block. So using $gateway['ipprotocol'] is the better option.
219
		 */
220
		if ($gateway['ipprotocol'] == "inet") { // This is an IPv4 gateway...
221
			$gwifip = find_interface_ip($gateway['interface'], true);
222
			if (!is_ipaddrv4($gwifip)) {
223
				continue; //Skip this target
224
			}
225

    
226
			if ($gwifip == "0.0.0.0") {
227
				continue; //Skip this target - the gateway is still waiting for DHCP
228
			}
229

    
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_ipaddrv4($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
				$route_to = "-host {$gateway['monitor']}";
239
				if (interface_isppp_type($gateway['friendlyiface'])) {
240
					route_add_or_change("{$route_to} -iface {$gateway['interface']}");
241
				} else {
242
					route_add_or_change("{$route_to} {$gateway['gateway']}");
243
				}
244

    
245
				pfSense_kill_states("0.0.0.0/0", $gateway['monitor'], $gateway['interface'], "icmp");
246
			}
247
		} else if ($gateway['ipprotocol'] == "inet6") { // This is an IPv6 gateway...
248
			if (is_linklocal($gateway['gateway']) &&
249
			    get_ll_scope($gateway['gateway']) == '') {
250
				$gateway['gateway'] .= '%' . $gateway['interface'];
251
			}
252

    
253
			if (is_linklocal($gateway['monitor'])) {
254
				if (get_ll_scope($gateway['monitor']) == '') {
255
					$gateways_arr[$gwname]['monitor'] .= '%' . $gateway['interface'];
256
				}
257

    
258
				$gwifip = find_interface_ipv6_ll($gateway['interface'], true);
259

    
260
				if (get_ll_scope($gwifip) == '') {
261
					$gwifip .= '%' . $gateway['interface'];
262
				}
263
			} else {
264
				$gwifip = find_interface_ipv6($gateway['interface'], true);
265
			}
266

    
267
			if (!is_ipaddrv6($gwifip)) {
268
				continue; //Skip this target
269
			}
270

    
271
			/*
272
			 * If the gateway is the same as the monitor we do not add a
273
			 * route as this will break the routing table.
274
			 * Add static routes for each gateway with their monitor IP
275
			 * not strictly necessary but is a added level of protection.
276
			 */
277
			if ($gateway['gateway'] != $gateway['monitor']) {
278
				log_error(sprintf(gettext('Removing static route for monitor %1$s and adding a new route through %2$s'), $gateway['monitor'], $gateway['gateway']));
279
				$route_to = "-host -inet6 {$gateway['monitor']}";
280
				if (interface_isppp_type($gateway['friendlyiface'])) {
281
					route_add_or_change("{$route_to} -iface {$gateway['interface']}");
282
				} else {
283
					route_add_or_change("{$route_to} {$gateway['gateway']}");
284
				}
285

    
286
				pfSense_kill_states("::0.0.0.0/0", $gateway['monitor'], $gateway['interface'], "icmpv6");
287
			}
288
		} else {
289
			continue;
290
		}
291

    
292
		$monitor_ips[] = $gateway['monitor'];
293
		$gateways_arr[$gwname]['enable_dpinger'] = true;
294
		$gateways_arr[$gwname]['gwifip'] = $gwifip;
295
	}
296

    
297
	stop_dpinger();
298

    
299
	/* Start new processes */
300
	foreach ($gateways_arr as $gateway) {
301
		if (!isset($gateway['enable_dpinger'])) {
302
			continue;
303
		}
304

    
305
		if (start_dpinger($gateway) != 0) {
306
			log_error(sprintf(gettext("Error starting gateway monitor for %s"), $gateway['name']));
307
		}
308
	}
309

    
310
	return;
311
}
312

    
313
function get_dpinger_status($gwname, $detailed = false) {
314
	global $g;
315

    
316
	$running_processes = running_dpinger_processes();
317

    
318
	if (!isset($running_processes[$gwname])) {
319
		log_error(sprintf(gettext('dpinger: No dpinger session running for gateway %s'), $gwname));
320
		return false;
321
	}
322

    
323
	$proc = $running_processes[$gwname];
324
	unset($running_processes);
325

    
326
	$timeoutcounter = 0;
327
	while (true) {
328
		if (!file_exists($proc['socket'])) {
329
			log_error("dpinger: status socket {$proc['socket']} not found");
330
			return false;
331
		}
332
		$fp = @stream_socket_client("unix://{$proc['socket']}", $errno, $errstr, 10);
333
		if (!$fp) {
334
			log_error(sprintf(gettext('dpinger: cannot connect to status socket %1$s - %2$s (%3$s)'), $proc['socket'], $errstr, $errno));
335
			return false;
336
		}
337

    
338
		$status = '';
339
		while (!feof($fp)) {
340
			$status .= fgets($fp, 1024);
341
		}
342
		fclose($fp);
343

    
344
		$r = array();
345
		list(
346
			$r['gwname'],
347
			$r['latency_avg'],
348
			$r['latency_stddev'],
349
			$r['loss']
350
		) = explode(' ', preg_replace('/\n/', '', $status));
351

    
352
		// dpinger returns '<gwname> 0 0 0' when queried directly after it starts.
353
		// while a latency of 0 and a loss of 0 would be perfect, in a real world it doesnt happen.
354
		// or does it, anyone? if so we must 'detect' the initialization period differently..
355
		$ready = $r['latency_stddev'] != '0' || $r['loss'] != '0';
356
		
357
		if ($ready) {
358
			break;
359
		} else {
360
			$timeoutcounter++;
361
			if ($timeoutcounter > 300) {
362
				log_error(sprintf(gettext('dpinger: timeout while retrieving status for gateway %s'), $gwname));
363
				return false;
364
			}
365
			usleep(10000);
366
		}
367
	}
368

    
369
	$r['srcip'] = $proc['srcip'];
370
	$r['targetip'] = $proc['targetip'];
371

    
372
	$gateways_arr = return_gateways_array();
373
	unset($gw);
374
	if (isset($gateways_arr[$gwname])) {
375
		$gw = $gateways_arr[$gwname];
376
	}
377

    
378
	$r['latency_avg'] = round($r['latency_avg']/1000, 3);
379
	$r['latency_stddev'] = round($r['latency_stddev']/1000, 3);
380

    
381
	$r['status'] = "none";
382
	if (isset($gw) && isset($gw['force_down'])) {
383
		$r['status'] = "force_down";
384
	} else if (isset($gw)) {
385
		$settings = return_dpinger_defaults();
386

    
387
		$keys = array(
388
		    'latencylow',
389
		    'latencyhigh',
390
		    'losslow',
391
		    'losshigh'
392
		);
393

    
394
		/* Replace default values by user-defined */
395
		foreach ($keys as $key) {
396
			if (isset($gw[$key]) && is_numeric($gw[$key])) {
397
				$settings[$key] = $gw[$key];
398
			}
399
		}
400

    
401
		if ($r['latency_avg'] > $settings['latencyhigh']) {
402
			if ($detailed) {
403
				$r['status'] = "highdelay";
404
			} else {
405
				$r['status'] = "down";
406
			}
407
		} else if ($r['loss'] > $settings['losshigh']) {
408
			if ($detailed) {
409
				$r['status'] = "highloss";
410
			} else {
411
				$r['status'] = "down";
412
			}
413
		} else if ($r['latency_avg'] > $settings['latencylow']) {
414
			$r['status'] = "delay";
415
		} else if ($r['loss'] > $settings['losslow']) {
416
			$r['status'] = "loss";
417
		}
418
	}
419

    
420
	return $r;
421
}
422

    
423
/* return the status of the dpinger targets as an array */
424
function return_gateways_status($byname = false) {
425
	global $config, $g;
426

    
427
	$dpinger_gws = running_dpinger_processes();
428
	$status = array();
429

    
430
	$gateways_arr = return_gateways_array();
431

    
432
	foreach ($dpinger_gws as $gwname => $gwdata) {
433
		// If action is disabled for this gateway, then we want a detailed status.
434
		// That reports "highdelay" or "highloss" rather than just "down".
435
		// Because reporting the gateway down would be misleading (gateway action is disabled)
436
		$detailed = $gateways_arr[$gwname]['action_disable'];
437
		$dpinger_status = get_dpinger_status($gwname, $detailed);
438
		if ($dpinger_status === false) {
439
			continue;
440
		}
441

    
442
		if ($byname == false) {
443
			$target = $dpinger_status['targetip'];
444
		} else {
445
			$target = $gwname;
446
		}
447

    
448
		$status[$target] = array();
449
		$status[$target]['monitorip'] = $dpinger_status['targetip'];
450
		$status[$target]['srcip'] = $dpinger_status['srcip'];
451
		$status[$target]['name'] = $gwname;
452
		$status[$target]['delay'] = empty($dpinger_status['latency_avg']) ? "0ms" : $dpinger_status['latency_avg'] . "ms";
453
		$status[$target]['stddev'] = empty($dpinger_status['latency_stddev']) ? "0ms" : $dpinger_status['latency_stddev'] . "ms";
454
		$status[$target]['loss'] = empty($dpinger_status['loss']) ? "0.0%" : round($dpinger_status['loss'], 1) . "%";
455
		$status[$target]['status'] = $dpinger_status['status'];
456
	}
457

    
458
	/* tack on any gateways that have monitoring disabled
459
	 * or are down, which could cause gateway groups to fail */
460
	$gateways_arr = return_gateways_array();
461
	foreach ($gateways_arr as $gwitem) {
462
		if (!isset($gwitem['monitor_disable'])) {
463
			continue;
464
		}
465
		if (!is_ipaddr($gwitem['monitor'])) {
466
			$realif = $gwitem['interface'];
467
			$tgtip = get_interface_gateway($realif);
468
			if (!is_ipaddr($tgtip)) {
469
				$tgtip = "none";
470
			}
471
			$srcip = find_interface_ip($realif);
472
		} else {
473
			$tgtip = $gwitem['monitor'];
474
			$srcip = find_interface_ip($realif);
475
		}
476
		if ($byname == true) {
477
			$target = $gwitem['name'];
478
		} else {
479
			$target = $tgtip;
480
		}
481

    
482
		/* failsafe for down interfaces */
483
		if ($target == "none") {
484
			$target = $gwitem['name'];
485
			$status[$target]['name'] = $gwitem['name'];
486
			$status[$target]['delay'] = "0.0ms";
487
			$status[$target]['loss'] = "100.0%";
488
			$status[$target]['status'] = "down";
489
		} else {
490
			$status[$target]['monitorip'] = $tgtip;
491
			$status[$target]['srcip'] = $srcip;
492
			$status[$target]['name'] = $gwitem['name'];
493
			$status[$target]['delay'] = "";
494
			$status[$target]['loss'] = "";
495
			$status[$target]['status'] = "none";
496
		}
497

    
498
		$status[$target]['monitor_disable'] = true;
499
	}
500
	return($status);
501
}
502

    
503
function return_gateways_status_text($byname = false, $brief = false) {
504
	$gwstat = return_gateways_status($byname);
505
	$output = "";
506
	$widths = array();
507
	$col_sep = 2;
508
	if ($brief) {
509
		$collist = array('status' => "Status");
510
	} else {
511
		$collist = array('monitorip' => "Monitor",
512
				'srcip' => "Source",
513
				'delay' => "Delay",
514
				'stddev' => "StdDev",
515
				'loss' => "Loss",
516
				'status' => "Status");
517
	}
518
	foreach ($gwstat as $gw) {
519
		foreach ($gw as $gwdidx => $gwdata) {
520
			if (strlen($gwdata) > $widths[$gwdidx]) {
521
				$widths[$gwdidx] = strlen($gwdata);
522
			}
523
		}
524
	}
525

    
526
	$output .= str_pad("Name", $widths['name'] + $col_sep, " ", STR_PAD_RIGHT);
527
	foreach ($collist as $hdrcol => $hdrdesc) {
528
		if (strlen($hdrdesc) > $widths[$hdrcol]) {
529
			$widths[$hdrcol] = strlen($hdrdesc);
530
		}
531
		$output .= str_pad($hdrdesc, $widths[$hdrcol] + $col_sep, " ", (substr($hdrcol, -2, 2) == "ip") ? STR_PAD_RIGHT : STR_PAD_LEFT);
532
	}
533
	$output .= "\n";
534

    
535
	foreach ($gwstat as $idx => $gw) {
536
		$output .= str_pad($gw['name'], $widths['name'] + $col_sep, " ", STR_PAD_RIGHT);
537
		foreach (array_keys($collist) as $col) {
538
			$output .= str_pad($gw[$col], $widths[$col] + $col_sep, " ", (substr($col, -2, 2) == "ip") ? STR_PAD_RIGHT : STR_PAD_LEFT);
539
		}
540
		$output .= "\n";
541
	}
542

    
543
	return $output;
544
}
545

    
546
/* Return all configured gateways on the system
547
   $disabled = true - include gateways that are disabled
548
   $localhost = true - include "Null" entries for localhost IP addresses
549
   $inactive = true - include gateways on inactive interfaces
550
   $integer_index = true - index the returned array by integers 0,1,2,... instead of by GW name
551
*/
552
function return_gateways_array($disabled = false, $localhost = false, $inactive = false, $integer_index = false) {
553
	global $config, $g;
554

    
555
	$gateways_arr = array();
556
	$gateways_arr_temp = array();
557

    
558
	$found_defaultv4 = 0;
559
	$found_defaultv6 = 0;
560

    
561
	// Ensure the interface cache is up to date first
562
	$interfaces = get_interface_arr(true);
563

    
564
	$i = -1;
565
	/* Process/add all the configured gateways. */
566
	if (is_array($config['gateways']['gateway_item'])) {
567
		foreach ($config['gateways']['gateway_item'] as $gateway) {
568
			/* Increment it here to do not skip items */
569
			$i++;
570

    
571
			if (empty($config['interfaces'][$gateway['interface']])) {
572
				if ($inactive === false) {
573
					continue;
574
				} else {
575
					$gateway['inactive'] = true;
576
				}
577
			}
578
			$wancfg = $config['interfaces'][$gateway['interface']];
579

    
580
			/* skip disabled interfaces */
581
			if ($disabled === false && (!isset($wancfg['enable']))) {
582
				continue;
583
			}
584

    
585
			/* if the gateway is dynamic and we can find the IPv4, Great! */
586
			if (empty($gateway['gateway']) || $gateway['gateway'] == "dynamic") {
587
				if ($gateway['ipprotocol'] == "inet") {
588
					/* we know which interfaces is dynamic, this should be made a function */
589
					$gateway['gateway'] = get_interface_gateway($gateway['interface']);
590
					/* no IP address found, set to dynamic */
591
					if (!is_ipaddrv4($gateway['gateway'])) {
592
						$gateway['gateway'] = "dynamic";
593
					}
594
					$gateway['dynamic'] = true;
595
				}
596

    
597
				/* if the gateway is dynamic and we can find the IPv6, Great! */
598
				else if ($gateway['ipprotocol'] == "inet6") {
599
					/* we know which interfaces is dynamic, this should be made a function, and for v6 too */
600
					$gateway['gateway'] = get_interface_gateway_v6($gateway['interface']);
601
					/* no IPv6 address found, set to dynamic */
602
					if (!is_ipaddrv6($gateway['gateway'])) {
603
						$gateway['gateway'] = "dynamic";
604
					}
605
					$gateway['dynamic'] = true;
606
				}
607
			} else {
608
				/* getting this detection right is hard at this point because we still don't
609
				 * store the address family in the gateway item */
610
				if (is_ipaddrv4($gateway['gateway'])) {
611
					$gateway['ipprotocol'] = "inet";
612
				} else if (is_ipaddrv6($gateway['gateway'])) {
613
					$gateway['ipprotocol'] = "inet6";
614
				}
615
			}
616

    
617
			if (isset($gateway['monitor_disable'])) {
618
				$gateway['monitor_disable'] = true;
619
			} else if (empty($gateway['monitor'])) {
620
				$gateway['monitor'] = $gateway['gateway'];
621
			}
622

    
623
			if (isset($gateway['action_disable'])) {
624
				$gateway['action_disable'] = true;
625
			}
626

    
627
			$gateway['friendlyiface'] = $gateway['interface'];
628

    
629
			/* special treatment for tunnel interfaces */
630
			if ($gateway['ipprotocol'] == "inet6") {
631
				$gateway['interface'] = get_real_interface($gateway['interface'], "inet6", false, false);
632
			} else {
633
				$gateway['interface'] = get_real_interface($gateway['interface'], "inet", false, false);
634
			}
635

    
636
			/* entry has a default flag, use it */
637
			if (isset($gateway['defaultgw'])) {
638
				if ($gateway['ipprotocol'] == "inet") {
639
					$gateway['defaultgw'] = true;
640
					$found_defaultv4 = 1;
641
				} else if ($gateway['ipprotocol'] == "inet6") {
642
					$gateway['defaultgw'] = true;
643
					$found_defaultv6 = 1;
644
				}
645
			}
646
			/* include the gateway index as the attribute */
647
			$gateway['attribute'] = $i;
648

    
649
			/* Remember all the gateway names, even ones to be skipped because they are disabled. */
650
			/* Then we can easily know and match them later when attempting to add dynamic gateways to the list. */
651
			$gateways_arr_temp[$gateway['name']] = $gateway;
652

    
653
			/* skip disabled gateways if the caller has not asked for them to be returned. */
654
			if (!($disabled === false && isset($gateway['disabled']))) {
655
				$gateways_arr[$gateway['name']] = $gateway;
656
			}
657
		}
658
	}
659
	unset($gateway);
660
	
661
	//Sort the array by GW name before moving on.
662
	ksort($gateways_arr, SORT_STRING | SORT_FLAG_CASE);
663

    
664
	/* Loop through all interfaces with a gateway and add it to a array */
665
	if ($disabled == false) {
666
		$iflist = get_configured_interface_with_descr();
667
	} else {
668
		$iflist = get_configured_interface_with_descr(true);
669
	}
670

    
671
	/* Process/add dynamic v4 gateways. */
672
	foreach ($iflist as $ifname => $friendly) {
673
		if (!interface_has_gateway($ifname)) {
674
			continue;
675
		}
676

    
677
		if (empty($config['interfaces'][$ifname])) {
678
			continue;
679
		}
680

    
681
		$ifcfg = &$config['interfaces'][$ifname];
682
		if (!isset($ifcfg['enable'])) {
683
			continue;
684
		}
685

    
686
		if (!empty($ifcfg['ipaddr']) && is_ipaddrv4($ifcfg['ipaddr'])) {
687
			continue;
688
		}
689

    
690
		$ctype = "";
691
		switch ($ifcfg['ipaddr']) {
692
			case "dhcp":
693
			case "pppoe":
694
			case "l2tp":
695
			case "pptp":
696
			case "ppp":
697
				$ctype = strtoupper($ifcfg['ipaddr']);
698
				break;
699
			default:
700
				$tunnelif = substr($ifcfg['if'], 0, 3);
701
				if (substr($ifcfg['if'], 0, 4) == "ovpn") {
702
					switch (substr($ifcfg['if'], 4, 1)) {
703
						case "c":
704
							$ovpntype = "openvpn-client";
705
							break;
706
						case "s":
707
							$ovpntype = "openvpn-server";
708
							break;
709
						default:
710
							// unknown ovpn type
711
							continue 2;
712
					}
713
					$ovpnid = substr($ifcfg['if'], 5);
714
					if (is_array($config['openvpn'][$ovpntype])) {
715
						foreach ($config['openvpn'][$ovpntype] as & $ovpnconf) {
716
							if ($ovpnconf['vpnid'] == $ovpnid) {
717
								// skip IPv6-only interfaces
718
								if ($ovpnconf['create_gw'] == "v6only") {
719
									continue 3;
720
								}
721
								// skip tap interfaces
722
								if ($ovpnconf['dev_mode'] == "tap") {
723
									continue 3;
724
								}
725
							}
726
						}
727
					}
728
					$ctype = "VPNv4";
729
				} else if ($tunnelif == "gif" || $tunnelif == "gre") {
730
					$ctype = "TUNNELv4";
731
				}
732
				break;
733
		}
734
		$ctype = "_". strtoupper($ctype);
735

    
736
		$gateway = array();
737
		$gateway['dynamic'] = false;
738
		$gateway['ipprotocol'] = "inet";
739
		$gateway['gateway'] = get_interface_gateway($ifname, $gateway['dynamic']);
740
		$gateway['interface'] = get_real_interface($ifname);
741
		$gateway['friendlyiface'] = $ifname;
742
		$gateway['name'] = "{$friendly}{$ctype}";
743
		$gateway['attribute'] = "system";
744

    
745
		if (($gateway['dynamic'] === "default") && ($found_defaultv4 == 0)) {
746
			$gateway['defaultgw'] = true;
747
			$gateway['dynamic'] = true;
748
			$found_defaultv4 = 1;
749
		}
750
		/* Loopback dummy for dynamic interfaces without a IP */
751
		if (!is_ipaddrv4($gateway['gateway']) && $gateway['dynamic'] == true) {
752
			$gateway['gateway'] = "dynamic";
753
		}
754

    
755
		/* automatically skip known static and dynamic gateways that were previously processed */
756
		foreach ($gateways_arr_temp as $gateway_item) {
757
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name'])&& ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
758
			    (($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))) {
759
				continue 2;
760
			}
761
		}
762

    
763
		if (is_ipaddrv4($gateway['gateway'])) {
764
			$gateway['monitor'] = $gateway['gateway'];
765
		}
766

    
767
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
768
		$gateways_arr[$gateway['name']] = $gateway;
769
	}
770
	unset($gateway);
771

    
772
	/* Process/add dynamic v6 gateways. */
773
	foreach ($iflist as $ifname => $friendly) {
774
		/* If the user has disabled IPv6, they probably don't want any IPv6 gateways. */
775
		if (!isset($config['system']['ipv6allow'])) {
776
			break;
777
		}
778

    
779
		if (!interface_has_gatewayv6($ifname)) {
780
			continue;
781
		}
782

    
783
		if (empty($config['interfaces'][$ifname])) {
784
			continue;
785
		}
786

    
787
		$ifcfg = &$config['interfaces'][$ifname];
788
		if (!isset($ifcfg['enable'])) {
789
			continue;
790
		}
791

    
792
		if (!empty($ifcfg['ipaddrv6']) && is_ipaddrv6($ifcfg['ipaddrv6'])) {
793
			continue;
794
		}
795

    
796
		$ctype = "";
797
		switch ($ifcfg['ipaddrv6']) {
798
			case "slaac":
799
			case "dhcp6":
800
			case "6to4":
801
			case "6rd":
802
				$ctype = strtoupper($ifcfg['ipaddrv6']);
803
				break;
804
			default:
805
				$tunnelif = substr($ifcfg['if'], 0, 3);
806
				if (substr($ifcfg['if'], 0, 4) == "ovpn") {
807
					switch (substr($ifcfg['if'], 4, 1)) {
808
						case "c":
809
							$ovpntype = "openvpn-client";
810
							break;
811
						case "s":
812
							$ovpntype = "openvpn-server";
813
							break;
814
						default:
815
							// unknown ovpn type
816
							continue 2;
817
					}
818
					$ovpnid = substr($ifcfg['if'], 5);
819
					if (is_array($config['openvpn'][$ovpntype])) {
820
						foreach ($config['openvpn'][$ovpntype] as & $ovpnconf) {
821
							if ($ovpnconf['vpnid'] == $ovpnid) {
822
								// skip IPv4-only interfaces
823
								if ($ovpnconf['create_gw'] == "v4only") {
824
									continue 3;
825
								}
826
								// skip tap interfaces
827
								if ($ovpnconf['dev_mode'] == "tap") {
828
									continue 3;
829
								}
830
							}
831
						}
832
					}
833
					$ctype = "VPNv6";
834
				} else if ($tunnelif == "gif" || $tunnelif == "gre") {
835
					$ctype = "TUNNELv6";
836
				}
837
				break;
838
		}
839
		$ctype = "_". strtoupper($ctype);
840

    
841
		$gateway = array();
842
		$gateway['dynamic'] = false;
843
		$gateway['ipprotocol'] = "inet6";
844
		$gateway['gateway'] = get_interface_gateway_v6($ifname, $gateway['dynamic']);
845
		$gateway['interface'] = get_real_interface($ifname, "inet6");
846
		switch ($ifcfg['ipaddrv6']) {
847
			case "6rd":
848
			case "6to4":
849
				$gateway['dynamic'] = "default";
850
				break;
851
		}
852
		$gateway['friendlyiface'] = $ifname;
853
		$gateway['name'] = "{$friendly}{$ctype}";
854
		$gateway['attribute'] = "system";
855

    
856
		if (($gateway['dynamic'] === "default") && ($found_defaultv6 == 0)) {
857
			$gateway['defaultgw'] = true;
858
			$gateway['dynamic'] = true;
859
			$found_defaultv6 = 1;
860
		}
861

    
862
		/* Loopback dummy for dynamic interfaces without a IP */
863
		if (!is_ipaddrv6($gateway['gateway']) && $gateway['dynamic'] == true) {
864
			$gateway['gateway'] = "dynamic";
865
		}
866

    
867
		/* automatically skip known static and dynamic gateways that were previously processed */
868
		foreach ($gateways_arr_temp as $gateway_item) {
869
			if ((($ifname == $gateway_item['friendlyiface'] && $friendly == $gateway_item['name']) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol'])) ||
870
			    (($ifname == $gateway_item['friendlyiface'] && $gateway_item['dynamic'] == true) && ($gateway['ipprotocol'] == $gateway_item['ipprotocol']))) {
871
				continue 2;
872
			}
873
		}
874

    
875
		if (is_ipaddrv6($gateway['gateway'])) {
876
			$gateway['monitor'] = $gateway['gateway'];
877
		}
878

    
879
		$gateway['descr'] = "Interface {$friendly}{$ctype} Gateway";
880
		$gateways_arr[$gateway['name']] = $gateway;
881
	}
882
	unset($gateway);
883

    
884
	/* FIXME: Should this be enabled.
885
	 * Some interface like wan might be default but have no info recorded
886
	 * the config. */
887
	/* this is a fallback if all else fails and we want to get packets out @smos */
888
	if ($found_defaultv4 == 0 || $found_defaultv6 == 0) {
889
		foreach ($gateways_arr as &$gateway) {
890
			if (($gateway['friendlyiface'] == "wan") && ($found_defaultv4 == 0) && (!isset($gateway['ipprotocol']) || ($gateway['ipprotocol'] == "inet"))) {
891
				if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgw")) {
892
					$gateway['defaultgw'] = true;
893
					$found_defaultv4 = 1;
894
				}
895
			}
896
			else if (($gateway['friendlyiface'] == "wan") && ($found_defaultv6 == 0) && ($gateway['ipprotocol'] == "inet6")) {
897
				if (file_exists("{$g['tmp_path']}/{$gateway['interface']}_defaultgwv6")) {
898
					$gateway['defaultgw'] = true;
899
					$found_defaultv6 = 1;
900
				}
901
			}
902
		}
903
	}
904

    
905
	if ($localhost === true) {
906
		/* attach localhost for Null routes */
907
		$gwlo4 = array();
908
		$gwlo4['name'] = "Null4";
909
		$gwlo4['interface'] = "lo0";
910
		$gwlo4['ipprotocol'] = "inet";
911
		$gwlo4['gateway'] = "127.0.0.1";
912
		$gwlo6 = array();
913
		$gwlo6['name'] = "Null6";
914
		$gwlo6['interface'] = "lo0";
915
		$gwlo6['ipprotocol'] = "inet6";
916
		$gwlo6['gateway'] = "::1";
917
		$gateways_arr['Null4'] = $gwlo4;
918
		$gateways_arr['Null6'] = $gwlo6;
919
	}
920

    
921
	if ($integer_index) {
922
		$gateways_arr = array_values($gateways_arr);
923
	}
924

    
925
	return($gateways_arr);
926
}
927

    
928
function fixup_default_gateway($ipprotocol, $gateways_status, $gateways_arr) {
929
	global $config, $g;
930
	/*
931
	 * NOTE: The code below is meant to replace the default gateway when it goes down.
932
	 *	This facilitates services running on pfSense itself and are not handled by a PBR to continue working.
933
	 */
934
	$upgw = '';
935
	$dfltgwname = '';
936
	$dfltgwdown = false;
937
	$dfltgwfound = false;
938
	foreach ($gateways_arr as $gwname => $gwsttng) {
939
		if (($gwsttng['ipprotocol'] == $ipprotocol) && isset($gwsttng['defaultgw'])) {
940
			$dfltgwfound = true;
941
			$dfltgwname = $gwname;
942
			if (!isset($gwsttng['monitor_disable']) && !isset($gwsttng['action_disable']) && $gateways_status[$gwname]['status'] != "none") {
943
				$dfltgwdown = true;
944
			}
945
		}
946
		/* Keep a record of the last up gateway */
947
		/* XXX: Blacklist lan for now since it might cause issues to those who have a gateway set for it */
948
		if (empty($upgw) && ($gwsttng['ipprotocol'] == $ipprotocol) && (isset($gwsttng['monitor_disable']) || isset($gwsttng['action_disable']) || $gateways_status[$gwname]['status'] == "none") && $gwsttng[$gwname]['friendlyiface'] != "lan") {
949
			$upgw = $gwname;
950
		}
951
		if ($dfltgwdown == true && !empty($upgw)) {
952
			break;
953
		}
954
	}
955
	if ($dfltgwfound == false) {
956
		$gwname = convert_friendly_interface_to_friendly_descr("wan");
957
		if (!empty($gateways_status[$gwname]) && stristr($gateways_status[$gwname]['status'], "down")) {
958
			$dfltgwdown = true;
959
		}
960
	}
961
	if ($dfltgwdown == true && !empty($upgw)) {
962
		if ($gateways_arr[$upgw]['gateway'] == "dynamic") {
963
			$gateways_arr[$upgw]['gateway'] = get_interface_gateway($gateways_arr[$upgw]['friendlyiface']);
964
		}
965
		if (is_ipaddr($gateways_arr[$upgw]['gateway'])) {
966
			log_error("Default gateway down setting {$upgw} as default!");
967
			if (is_ipaddrv6($gateways_arr[$upgw]['gateway'])) {
968
				$inetfamily = "-inet6";
969
				if (is_linklocal($gateways_arr[$upgw]['gateway']) && get_ll_scope($gateways_arr[$upgw]['gateway']) == '') {
970
					$gateways_arr[$upgw]['gateway'] .= "%" . $gateways_arr[$upgw]['interface'];
971
				}
972
			} else {
973
				$inetfamily = "-inet";
974
			}
975
			route_add_or_change("{$inetfamily} default {$gateways_arr[$upgw]['gateway']}");
976
		}
977
	} else if (!empty($dfltgwname)) {
978
		$defaultgw = trim(exec("/sbin/route -n get -{$ipprotocol} default | /usr/bin/awk '/gateway:/ {print $2}'"), " \n");
979
		if ($ipprotocol == 'inet6' && !is_ipaddrv6($gateways_arr[$dfltgwname]['gateway'])) {
980
			return;
981
		}
982
		if ($ipprotocol == 'inet' && !is_ipaddrv4($gateways_arr[$dfltgwname]['gateway'])) {
983
			return;
984
		}
985
		if ($ipprotocol == 'inet6') {
986
			if (is_linklocal($gateways_arr[$upgw]['gateway']) && get_ll_scope($gateways_arr[$upgw]['gateway']) == '') {
987
				$gateways_arr[$upgw]['gateway'] .= "%" . $gateways_arr[$upgw]['interface'];
988
			}
989
			if (is_linklocal($gateways_arr[$dfltgwname]['gateway']) && get_ll_scope($gateways_arr[$dfltgwname]['gateway']) == '') {
990
				$gateways_arr[$dfltgwname]['gateway'] .= "%" . $gateways_arr[$dfltgwname]['interface'];
991
			}
992
		}
993
		if ($defaultgw != $gateways_arr[$dfltgwname]['gateway']) {
994
			route_add_or_change("-{$ipprotocol} default {$gateways_arr[$dfltgwname]['gateway']}");
995
		}
996
	}
997
}
998

    
999
/*
1000
 * Return an array with all gateway groups with name as key
1001
 * All gateway groups will be processed before returning the array.
1002
 */
1003
function return_gateway_groups_array() {
1004
	global $config, $g;
1005

    
1006
	/* fetch the current gateways status */
1007
	$gateways_status = return_gateways_status(true);
1008
	$gateways_arr = return_gateways_array();
1009
	$gateway_groups_array = array();
1010

    
1011
	if (isset($config['system']['gw_switch_default'])) {
1012
		fixup_default_gateway("inet", $gateways_status, $gateways_arr);
1013
		fixup_default_gateway("inet6", $gateways_status, $gateways_arr);
1014
	}
1015
	if (is_array($config['gateways']['gateway_group'])) {
1016
		$viplist = get_configured_vip_list();
1017
		foreach ($config['gateways']['gateway_group'] as $group) {
1018
			$gateway_groups_array[$group['name']]['descr'] = $group['descr'];
1019
			/* create array with group gateways members separated by tier */
1020
			$tiers = array();
1021
			$backupplan = array();
1022
			$gwvip_arr = array();
1023
			foreach ($group['item'] as $item) {
1024
				list($gwname, $tier, $vipname) = explode("|", $item);
1025

    
1026
				if (is_ipaddr($viplist[$vipname])) {
1027
					if (!is_array($gwvip_arr[$group['name']])) {
1028
						$gwvip_arr[$group['name']] = array();
1029
					}
1030
					$gwvip_arr[$group['name']][$gwname] = $vipname;
1031
				}
1032

    
1033
				/* Do it here rather than reiterating again the group in case no member is up. */
1034
				if (!is_array($backupplan[$tier])) {
1035
					$backupplan[$tier] = array();
1036
				}
1037
				$backupplan[$tier][] = $gwname;
1038

    
1039
				/* check if the gateway is available before adding it to the array */
1040
				if (is_array($gateways_status[$gwname])) {
1041
					$status = $gateways_status[$gwname];
1042
					$gwdown = false;
1043
					if (stristr($status['status'], "down")) {
1044
						$msg = sprintf(gettext('MONITOR: %1$s is down, omitting from routing group %2$s'), $gwname, $group['name']);
1045
						$gwdown = true;
1046
					} else if (stristr($status['status'], "loss") && strstr($group['trigger'], "loss")) {
1047
						/* packet loss */
1048
						$msg = sprintf(gettext('MONITOR: %1$s has packet loss, omitting from routing group %2$s'), $gwname, $group['name']);
1049
						$gwdown = true;
1050
					} else if (stristr($status['status'], "delay") && strstr($group['trigger'] , "latency")) {
1051
						/* high latency */
1052
						$msg = sprintf(gettext('MONITOR: %1$s has high latency, omitting from routing group %2$s'), $gwname, $group['name']);
1053
						$gwdown = true;
1054
					}
1055
					$pluginparams = array();
1056
					$pluginparams['type'] = 'gateway';
1057
					$pluginparams['name'] = ${gwname};
1058
					if ($gwdown == true) {
1059
						$pluginparams['event'] = 'gateway.down';
1060
						if (!file_exists("/tmp/.down.{$gwname}")) {
1061
							$msg .= "\n".implode("|", $status);
1062
							touch("/tmp/.down.{$gwname}");
1063
							log_error($msg);
1064
							notify_via_growl($msg);
1065
							notify_via_smtp($msg);
1066
						}
1067
					} else {
1068
						$pluginparams['event'] = 'gateway.up';
1069
						/* Online add member */
1070
						if (!is_array($tiers[$tier])) {
1071
							$tiers[$tier] = array();
1072
						}
1073
						$tiers[$tier][] = $gwname;
1074
						if (unlink_if_exists("/tmp/.down.{$gwname}")) {
1075
							$msg = sprintf(gettext('MONITOR: %1$s is available now, adding to routing group %2$s'), $gwname, $group['name']);
1076
							$msg .= "\n".implode("|", $status);
1077
							log_error($msg);
1078
							notify_via_growl($msg);
1079
							notify_via_smtp($msg);
1080
						}
1081
					}
1082
					if (isset($gateways_arr[$gwname]['interface']))
1083
						$pluginparams['interface'] = $gateways_arr[$gwname]['interface'];
1084
					pkg_call_plugins('plugin_gateway', $pluginparams);
1085
				} else if (isset($gateways_arr[$gwname]['monitor_disable']) || isset($gateways_arr[$gwname]['action_disable'])) {
1086
					$tiers[$tier][] = $gwname;
1087
				}
1088
			}
1089
			$tiers_count = count($tiers);
1090
			if ($tiers_count == 0) {
1091
				/* Oh dear, we have no members! Engage Plan B */
1092
				if (!platform_booting()) {
1093
					$msg = sprintf(gettext('Gateways status could not be determined, considering all as up/active. (Group: %s)'), $group['name']);
1094
					log_error($msg);
1095
					notify_via_growl($msg);
1096
					//notify_via_smtp($msg);
1097
				}
1098
				$tiers = $backupplan;
1099
			}
1100
			/* sort the tiers array by the tier key */
1101
			ksort($tiers);
1102

    
1103
			/* we do not really foreach the tiers as we stop after the first tier */
1104
			foreach ($tiers as $tieridx => $tier) {
1105
				/* process all gateways in this tier */
1106
				foreach ($tier as $member) {
1107
					/* determine interface gateway */
1108
					if (isset($gateways_arr[$member])) {
1109
						$gateway = $gateways_arr[$member];
1110
						$int = $gateway['interface'];
1111
						$gatewayip = "";
1112
						if (is_ipaddr($gateway['gateway'])) {
1113
							$gatewayip = $gateway['gateway'];
1114
						} else if (!empty($int)) {
1115
							$gatewayip = get_interface_gateway($gateway['friendlyiface']);
1116
						}
1117

    
1118
						if (!empty($int)) {
1119
							$gateway_groups_array[$group['name']]['ipprotocol'] = $gateway['ipprotocol'];
1120
							if (is_ipaddr($gatewayip)) {
1121
								$groupmember = array();
1122
								$groupmember['int'] = $int;
1123
								$groupmember['gwip'] = $gatewayip;
1124
								$groupmember['weight'] = isset($gateway['weight']) ? $gateway['weight'] : 1;
1125
								if (is_array($gwvip_arr[$group['name']]) && !empty($gwvip_arr[$group['name']][$member]))
1126
									$groupmember['vip'] = $gwvip_arr[$group['name']][$member];
1127
								$gateway_groups_array[$group['name']][] = $groupmember;
1128
							}
1129
						}
1130
					}
1131
				}
1132
				/* we should have the 1st available tier now, exit stage left */
1133
				if (count($gateway_groups_array[$group['name']]) > 0) {
1134
					break;
1135
				} else {
1136
					log_error(sprintf(gettext('GATEWAYS: Group %1$s did not have any gateways up on tier %2$s!'), $group['name'], $tieridx));
1137
				}
1138
			}
1139
		}
1140
	}
1141

    
1142
	return ($gateway_groups_array);
1143
}
1144

    
1145
/* Update DHCP WAN Interface ip address in gateway group item */
1146
function dhclient_update_gateway_groups_defaultroute($interface = "wan") {
1147
	global $config, $g;
1148
	foreach ($config['gateways']['gateway_item'] as & $gw) {
1149
		if ($gw['interface'] == $interface) {
1150
			$current_gw = get_interface_gateway($interface);
1151
			if ($gw['gateway'] <> $current_gw) {
1152
				$gw['gateway'] = $current_gw;
1153
				$changed = true;
1154
			}
1155
		}
1156
	}
1157
	if ($changed && $current_gw) {
1158
		write_config(sprintf(gettext('Updating gateway group gateway for %1$s - new gateway is %2$s'), $interface, $current_gw));
1159
	}
1160
}
1161

    
1162
function lookup_gateway_ip_by_name($name, $disabled = false) {
1163

    
1164
	$gateways_arr = return_gateways_array($disabled, true);
1165
	foreach ($gateways_arr as $gname => $gw) {
1166
		if ($gw['name'] === $name || $gname === $name) {
1167
			return $gw['gateway'];
1168
		}
1169
	}
1170

    
1171
	return false;
1172
}
1173

    
1174
function lookup_gateway_monitor_ip_by_name($name) {
1175

    
1176
	$gateways_arr = return_gateways_array(false, true);
1177
	if (!empty($gateways_arr[$name])) {
1178
		$gateway = $gateways_arr[$name];
1179
		if (!is_ipaddr($gateway['monitor'])) {
1180
			return $gateway['gateway'];
1181
		}
1182

    
1183
		return $gateway['monitor'];
1184
	}
1185

    
1186
	return (false);
1187
}
1188

    
1189
function lookup_gateway_interface_by_name($name) {
1190

    
1191
	$gateways_arr = return_gateways_array(false, true);
1192
	if (!empty($gateways_arr[$name])) {
1193
		$interfacegw = $gateways_arr[$name]['friendlyiface'];
1194
		return ($interfacegw);
1195
	}
1196

    
1197
	return (false);
1198
}
1199

    
1200
function get_interface_gateway($interface, &$dynamic = false) {
1201
	global $config, $g;
1202

    
1203
	if (substr($interface, 0, 4) == '_vip') {
1204
		$interface = get_configured_vip_interface($interface);
1205
		if (substr($interface, 0, 4) == '_vip') {
1206
			$interface = get_configured_vip_interface($interface);
1207
		}
1208
	}
1209

    
1210
	$gw = NULL;
1211
	$gwcfg = $config['interfaces'][$interface];
1212
	if (!empty($gwcfg['gateway']) && is_array($config['gateways']['gateway_item'])) {
1213
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1214
			if (($gateway['name'] == $gwcfg['gateway']) && (is_ipaddrv4($gateway['gateway']))) {
1215
				$gw = $gateway['gateway'];
1216
				break;
1217
			}
1218
		}
1219
	}
1220

    
1221
	// for dynamic interfaces we handle them through the $interface_router file.
1222
	if (($gw == NULL || !is_ipaddrv4($gw)) && !is_ipaddrv4($gwcfg['ipaddr'])) {
1223
		$realif = get_real_interface($interface);
1224
		if (file_exists("{$g['tmp_path']}/{$realif}_router")) {
1225
			$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_router"), " \n");
1226
			$dynamic = true;
1227
		}
1228
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgw")) {
1229
			$dynamic = "default";
1230
		}
1231

    
1232
	}
1233

    
1234
	/* return gateway */
1235
	return ($gw);
1236
}
1237

    
1238
function get_interface_gateway_v6($interface, &$dynamic = false) {
1239
	global $config, $g;
1240

    
1241
	if (substr($interface, 0, 4) == '_vip') {
1242
		$interface = get_configured_vip_interface($interface);
1243
		if (substr($interface, 0, 4) == '_vip') {
1244
			$interface = get_configured_vip_interface($interface);
1245
		}
1246
	}
1247

    
1248
	$gw = NULL;
1249
	$gwcfg = $config['interfaces'][$interface];
1250
	if (!empty($gwcfg['gatewayv6']) && is_array($config['gateways']['gateway_item'])) {
1251
		foreach ($config['gateways']['gateway_item'] as $gateway) {
1252
			if (($gateway['name'] == $gwcfg['gatewayv6']) && (is_ipaddrv6($gateway['gateway']))) {
1253
				$gw = $gateway['gateway'];
1254
				break;
1255
			}
1256
		}
1257
	}
1258

    
1259
	// for dynamic interfaces we handle them through the $interface_router file.
1260
	if (($gw == NULL || !is_ipaddrv6($gw)) && !is_ipaddrv6($gwcfg['ipaddrv6'])) {
1261
		$realif = get_real_interface($interface);
1262
		if (file_exists("{$g['tmp_path']}/{$realif}_routerv6")) {
1263
			$gw = trim(file_get_contents("{$g['tmp_path']}/{$realif}_routerv6"), " \n");
1264
			$dynamic = true;
1265
		}
1266
		if (file_exists("{$g['tmp_path']}/{$realif}_defaultgwv6")) {
1267
			$dynamic = "default";
1268
		}
1269
	}
1270
	/* return gateway */
1271
	return ($gw);
1272
}
1273

    
1274
/* Check a IP address against a gateway IP or name
1275
 * to verify it's address family */
1276
function validate_address_family($ipaddr, $gwname, $disabled = false) {
1277
	$v4ip = false;
1278
	$v6ip = false;
1279
	$v4gw = false;
1280
	$v6gw = false;
1281

    
1282
	if (is_ipaddrv4($ipaddr)) {
1283
		$v4ip = true;
1284
	}
1285
	if (is_ipaddrv6($ipaddr)) {
1286
		$v6ip = true;
1287
	}
1288
	if (is_ipaddrv4($gwname)) {
1289
		$v4gw = true;
1290
	}
1291
	if (is_ipaddrv6($gwname)) {
1292
		$v6gw = true;
1293
	}
1294

    
1295
	if ($v4ip && $v4gw) {
1296
		return true;
1297
	}
1298
	if ($v6ip && $v6gw) {
1299
		return true;
1300
	}
1301

    
1302
	/* still no match, carry on, lookup gateways */
1303
	if (is_ipaddrv4(lookup_gateway_ip_by_name($gwname, $disabled))) {
1304
		$v4gw = true;
1305
	}
1306
	if (is_ipaddrv6(lookup_gateway_ip_by_name($gwname, $disabled))) {
1307
		$v6gw = true;
1308
	}
1309

    
1310
	$gw_array = return_gateways_array();
1311
	if (is_array($gw_array[$gwname])) {
1312
		switch ($gw_array[$gwname]['ipprotocol']) {
1313
			case "inet":
1314
				$v4gw = true;
1315
				break;
1316
			case "inet6":
1317
				$v6gw = true;
1318
				break;
1319
		}
1320
	}
1321

    
1322
	if ($v4ip && $v4gw) {
1323
		return true;
1324
	}
1325
	if ($v6ip && $v6gw) {
1326
		return true;
1327
	}
1328

    
1329
	return false;
1330
}
1331

    
1332
/* check if a interface is part of a gateway group */
1333
function interface_gateway_group_member($interface, $gwgroup_name = "") {
1334
	global $config;
1335

    
1336
	if (is_array($config['gateways']['gateway_group'])) {
1337
		$groups = $config['gateways']['gateway_group'];
1338
	} else {
1339
		return false;
1340
	}
1341

    
1342
	$gateways_arr = return_gateways_array(false, true);
1343
	foreach ($groups as $group) {
1344
		if (is_array($group['item'])) {
1345
			foreach ($group['item'] as $item) {
1346
				$elements = explode("|", $item);
1347
				$gwname = $elements[0];
1348
				if ($interface == $gateways_arr[$gwname]['interface'] &&
1349
				    (empty($gwgroup_name) || $gwgroup_name == $group['name'])) {
1350
					unset($gateways_arr);
1351
					return true;
1352
				}
1353
			}
1354
		}
1355
	}
1356
	unset($gateways_arr);
1357

    
1358
	return false;
1359
}
1360

    
1361
function gateway_is_gwgroup_member($name) {
1362
	global $config;
1363

    
1364
	if (is_array($config['gateways']['gateway_group'])) {
1365
		$groups = $config['gateways']['gateway_group'];
1366
	} else {
1367
		return false;
1368
	}
1369

    
1370
	$members = array();
1371
	foreach ($groups as $group) {
1372
		if (is_array($group['item'])) {
1373
			foreach ($group['item'] as $item) {
1374
				$elements = explode("|", $item);
1375
				$gwname = $elements[0];
1376
				if ($name == $elements[0]) {
1377
					$members[] = $group['name'];
1378
				}
1379
			}
1380
		}
1381
	}
1382

    
1383
	return $members;
1384
}
1385
/*
1386
  Check the proposed gateway settings to see if they are valid.
1387
  $gateway_settings - the proposed array of proposed gateway settings
1388
  $id - the index of the gateway proposed to be modified (otherwise "" if adding a new gateway)
1389
  $parent_ip - the IP (v4 or v6) address about to be set on the corresponding interface (if any)
1390
  $parent_sn - the subnet about to be set on the corresponding interface (if any)
1391
  (Note: the above 2 parameters allow gateway parameters to be validated concurrently with saving
1392
   an interface, before the new interface parameters are actually saved in the config.)
1393
  Return completed $input_errors array if there is any problem.
1394
  Otherwise return an empty $input_errors array
1395
*/
1396
function validate_gateway($gateway_settings, $id = "", $parent_ip = "", $parent_sn = "") {
1397
	global $config;
1398

    
1399
	$a_gateways = return_gateways_array(true, false, true, true);
1400
	$input_errors = array();
1401

    
1402
	/* input validation */
1403
	$reqdfields = explode(" ", "name interface");
1404
	$reqdfieldsn = array(gettext("Name"), gettext("Interface"));
1405

    
1406
	do_input_validation($gateway_settings, $reqdfields, $reqdfieldsn, $input_errors);
1407

    
1408
	if (!isset($gateway_settings['name'])) {
1409
		$input_errors[] = "A valid gateway name must be specified.";
1410
	}
1411
	if (!is_validaliasname($gateway_settings['name'])) {
1412
		$input_errors[] = invalidaliasnamemsg($gateway_settings['name'], gettext("gateway"));
1413
	} else if (isset($gateway_settings['disabled'])) {
1414
		// We have a valid gateway name that the user wants to mark as disabled.
1415
		// Check if the gateway name is used in any gateway group.
1416
		if (is_array($config['gateways']['gateway_group'])) {
1417
			foreach ($config['gateways']['gateway_group'] as $group) {
1418
				foreach ($group['item'] as $item) {
1419
					$items = explode("|", $item);
1420
					if ($items[0] == $gateway_settings['name']) {
1421
						$input_errors[] = sprintf(gettext('Gateway "%1$s" cannot be disabled because it is in use on Gateway Group "%2$s"'), $gateway_settings['name'], $group['name']);
1422
					}
1423
				}
1424
			}
1425
		}
1426

    
1427
		// Check if the gateway name is used in any enabled Static Route.
1428
		if (is_array($config['staticroutes']['route'])) {
1429
			foreach ($config['staticroutes']['route'] as $route) {
1430
				if ($route['gateway'] == $gateway_settings['name']) {
1431
					if (!isset($route['disabled'])) {
1432
						// There is a static route that uses this gateway and is enabled (not disabled).
1433
						$input_errors[] = sprintf(gettext('Gateway "%1$s" cannot be disabled because it is in use on Static Route "%2$s"'), $gateway_settings['name'], $route['network']);
1434
					}
1435
				}
1436
			}
1437
		}
1438
	}
1439
	/* skip system gateways which have been automatically added */
1440
	if (($gateway_settings['gateway'] && (!is_ipaddr($gateway_settings['gateway'])) && ($gateway_settings['attribute'] !== "system")) && ($gateway_settings['gateway'] != "dynamic")) {
1441
		$input_errors[] = gettext("A valid gateway IP address must be specified.");
1442
	}
1443

    
1444
	if ($gateway_settings['gateway'] && is_ipaddr($gateway_settings['gateway'])) {
1445
		if (is_ipaddrv4($gateway_settings['gateway'])) {
1446
			if ($parent_ip == '') {
1447
				$parent_ip = get_interface_ip($gateway_settings['interface']);
1448
				$parent_sn = get_interface_subnet($gateway_settings['interface']);
1449
			}
1450
			if (empty($parent_ip) || empty($parent_sn)) {
1451
				$input_errors[] = gettext("Cannot add IPv4 Gateway Address because no IPv4 address could be found on the interface.");
1452
			} elseif (!isset($gateway_settings["nonlocalgateway"])) {
1453
				$subnets = array(gen_subnet($parent_ip, $parent_sn) . "/" . $parent_sn);
1454
				$vips = link_interface_to_vips($gateway_settings['interface']);
1455
				if (is_array($vips)) {
1456
					foreach ($vips as $vip) {
1457
						if (!is_ipaddrv4($vip['subnet'])) {
1458
							continue;
1459
						}
1460
						$subnets[] = gen_subnet($vip['subnet'], $vip['subnet_bits']) . "/" . $vip['subnet_bits'];
1461
					}
1462
				}
1463

    
1464
				$found = false;
1465
				foreach ($subnets as $subnet) {
1466
					if (ip_in_subnet($gateway_settings['gateway'], $subnet)) {
1467
						$found = true;
1468
						break;
1469
					}
1470
				}
1471

    
1472
				if ($found === false) {
1473
					$input_errors[] = sprintf(gettext("The gateway address %s does not lie within one of the chosen interface's subnets."), $gateway_settings['gateway']);
1474
				}
1475
			}
1476
		} else if (is_ipaddrv6($gateway_settings['gateway'])) {
1477
			/* do not do a subnet match on a link local address, it's valid */
1478
			if (!is_linklocal($gateway_settings['gateway'])) {
1479
				if ($parent_ip == '') {
1480
					$parent_ip = get_interface_ipv6($gateway_settings['interface']);
1481
					$parent_sn = get_interface_subnetv6($gateway_settings['interface']);
1482
				}
1483
				if (empty($parent_ip) || empty($parent_sn)) {
1484
					$input_errors[] = gettext("Cannot add IPv6 Gateway Address because no IPv6 address could be found on the interface.");
1485
				} elseif (!isset($gateway_settings["nonlocalgateway"])) {
1486
					$subnets = array(gen_subnetv6($parent_ip, $parent_sn) . "/" . $parent_sn);
1487
					$vips = link_interface_to_vips($gateway_settings['interface']);
1488
					if (is_array($vips)) {
1489
						foreach ($vips as $vip) {
1490
							if (!is_ipaddrv6($vip['subnet'])) {
1491
								continue;
1492
							}
1493
							$subnets[] = gen_subnetv6($vip['subnet'], $vip['subnet_bits']) . "/" . $vip['subnet_bits'];
1494
						}
1495
					}
1496

    
1497
					$found = false;
1498
					foreach ($subnets as $subnet) {
1499
						if (ip_in_subnet($gateway_settings['gateway'], $subnet)) {
1500
							$found = true;
1501
							break;
1502
						}
1503
					}
1504

    
1505
					if ($found === false) {
1506
						$input_errors[] = sprintf(gettext("The gateway address %s does not lie within one of the chosen interface's subnets."), $gateway_settings['gateway']);
1507
					}
1508
				}
1509
			}
1510
		}
1511

    
1512
		if (!empty($config['interfaces'][$gateway_settings['interface']]['ipaddr'])) {
1513
			if (is_ipaddr($config['interfaces'][$gateway_settings['interface']]['ipaddr']) && (empty($gateway_settings['gateway']) || $gateway_settings['gateway'] == "dynamic")) {
1514
				$input_errors[] = gettext("Dynamic gateway values cannot be specified for interfaces with a static IPv4 configuration.");
1515
			}
1516
		}
1517
		if (!empty($config['interfaces'][$gateway_settings['interface']]['ipaddrv6'])) {
1518
			if (is_ipaddr($config['interfaces'][$gateway_settings['interface']]['ipaddrv6']) && (empty($gateway_settings['gateway']) || $gateway_settings['gateway'] == "dynamic")) {
1519
				$input_errors[] = gettext("Dynamic gateway values cannot be specified for interfaces with a static IPv6 configuration.");
1520
			}
1521
		}
1522
	}
1523
	if (($gateway_settings['monitor'] != "") && ($gateway_settings['monitor'] != "dynamic")) {
1524
		validateipaddr($gateway_settings['monitor'], IPV4V6, "Monitor IP", $input_errors, false);
1525
	}
1526
	if (isset($gateway_settings['data_payload']) && is_numeric($gateway_settings['data_payload']) && $gateway_settings['data_payload'] < 0) {
1527
		$input_errors[] = gettext("A valid data payload must be specified.");
1528
	}
1529
	/* only allow correct IPv4 and IPv6 gateway addresses */
1530
	if (($gateway_settings['gateway'] <> "") && is_ipaddr($gateway_settings['gateway']) && $gateway_settings['gateway'] != "dynamic") {
1531
		if (is_ipaddrv6($gateway_settings['gateway']) && ($gateway_settings['ipprotocol'] == "inet")) {
1532
			$input_errors[] = sprintf(gettext("The IPv6 gateway address '%s' can not be used as a IPv4 gateway."), $gateway_settings['gateway']);
1533
		}
1534
		if (is_ipaddrv4($gateway_settings['gateway']) && ($gateway_settings['ipprotocol'] == "inet6")) {
1535
			$input_errors[] = sprintf(gettext("The IPv4 gateway address '%s' can not be used as a IPv6 gateway."), $gateway_settings['gateway']);
1536
		}
1537
	}
1538
	/* only allow correct IPv4 and IPv6 monitor addresses */
1539
	if (($gateway_settings['monitor'] <> "") && is_ipaddr($gateway_settings['monitor']) && $gateway_settings['monitor'] != "dynamic") {
1540
		if (is_ipaddrv6($gateway_settings['monitor']) && ($gateway_settings['ipprotocol'] == "inet")) {
1541
			$input_errors[] = sprintf(gettext("The IPv6 monitor address '%s' can not be used on a IPv4 gateway."), $gateway_settings['monitor']);
1542
		}
1543
		if (is_ipaddrv4($gateway_settings['monitor']) && ($gateway_settings['ipprotocol'] == "inet6")) {
1544
			$input_errors[] = sprintf(gettext("The IPv4 monitor address '%s' can not be used on a IPv6 gateway."), $gateway_settings['monitor']);
1545
		}
1546
	}
1547

    
1548
	if (isset($gateway_settings['name'])) {
1549
		/* check for overlaps */
1550
		foreach ($a_gateways as $gateway) {
1551
			if (isset($id) && ($a_gateways[$id]) && ($a_gateways[$id] === $gateway)) {
1552
				if ($gateway['name'] != $gateway_settings['name']) {
1553
					$input_errors[] = gettext("Changing name on a gateway is not allowed.");
1554
				}
1555
				continue;
1556
			}
1557
			if ($gateway_settings['name'] <> "") {
1558
				if (($gateway['name'] <> "") && ($gateway_settings['name'] == $gateway['name']) && ($gateway['attribute'] !== "system")) {
1559
					$input_errors[] = sprintf(gettext('The gateway name "%s" already exists.'), $gateway_settings['name']);
1560
					break;
1561
				}
1562
			}
1563
			if (is_ipaddr($gateway_settings['gateway'])) {
1564
				if (($gateway['gateway'] <> "") && ($gateway_settings['gateway'] == $gateway['gateway']) && ($gateway['attribute'] !== "system")) {
1565
					$input_errors[] = sprintf(gettext('The gateway IP address "%s" already exists.'), $gateway_settings['gateway']);
1566
					break;
1567
				}
1568
			}
1569
			if (is_ipaddr($gateway_settings['monitor'])) {
1570
				if (($gateway['monitor'] <> "") && ($gateway_settings['monitor'] == $gateway['monitor']) && ($gateway['attribute'] !== "system")) {
1571
					$input_errors[] = sprintf(gettext('The monitor IP address "%s" is already in use. A different monitor IP must be chosen.'), $gateway_settings['monitor']);
1572
					break;
1573
				}
1574
			}
1575
		}
1576
	}
1577

    
1578
	/* input validation of dpinger advanced parameters */
1579

    
1580
	$dpinger_default = return_dpinger_defaults();
1581
	$latencylow = $dpinger_default['latencylow'];
1582
	if ($gateway_settings['latencylow']) {
1583
		if (!is_numeric($gateway_settings['latencylow'])) {
1584
			$input_errors[] = gettext("The low latency threshold needs to be a numeric value.");
1585
		} else if ($gateway_settings['latencylow'] < 1) {
1586
			$input_errors[] = gettext("The low latency threshold needs to be positive.");
1587
		} else {
1588
			$latencylow = $gateway_settings['latencylow'];
1589
		}
1590
	}
1591

    
1592
	$latencyhigh = $dpinger_default['latencyhigh'];
1593
	if ($gateway_settings['latencyhigh']) {
1594
		if (!is_numeric($gateway_settings['latencyhigh'])) {
1595
			$input_errors[] = gettext("The high latency threshold needs to be a numeric value.");
1596
		} else if ($gateway_settings['latencyhigh'] < 1) {
1597
			$input_errors[] = gettext("The high latency threshold needs to be positive.");
1598
		} else {
1599
			$latencyhigh = $gateway_settings['latencyhigh'];
1600
		}
1601
	}
1602

    
1603
	$losslow = $dpinger_default['losslow'];
1604
	if ($gateway_settings['losslow']) {
1605
		if (!is_numeric($gateway_settings['losslow'])) {
1606
			$input_errors[] = gettext("The low Packet Loss threshold needs to be a numeric value.");
1607
		} else if ($gateway_settings['losslow'] < 1) {
1608
			$input_errors[] = gettext("The low Packet Loss threshold needs to be positive.");
1609
		} else if ($gateway_settings['losslow'] >= 100) {
1610
			$input_errors[] = gettext("The low Packet Loss threshold needs to be less than 100.");
1611
		} else {
1612
			$losslow = $gateway_settings['losslow'];
1613
		}
1614
	}
1615

    
1616
	$losshigh = $dpinger_default['losshigh'];
1617
	if ($gateway_settings['losshigh']) {
1618
		if (!is_numeric($gateway_settings['losshigh'])) {
1619
			$input_errors[] = gettext("The high Packet Loss threshold needs to be a numeric value.");
1620
		} else if ($gateway_settings['losshigh'] < 1) {
1621
			$input_errors[] = gettext("The high Packet Loss threshold needs to be positive.");
1622
		} else if ($gateway_settings['losshigh'] > 100) {
1623
			$input_errors[] = gettext("The high Packet Loss threshold needs to be 100 or less.");
1624
		} else {
1625
			$losshigh = $gateway_settings['losshigh'];
1626
		}
1627
	}
1628

    
1629
	$time_period = $dpinger_default['time_period'];
1630
	if ($gateway_settings['time_period']) {
1631
		if (!is_numeric($gateway_settings['time_period'])) {
1632
			$input_errors[] = gettext("The time period over which results are averaged needs to be a numeric value.");
1633
		} else if ($gateway_settings['time_period'] < 1) {
1634
			$input_errors[] = gettext("The time period over which results are averaged needs to be positive.");
1635
		} else {
1636
			$time_period = $gateway_settings['time_period'];
1637
		}
1638
	}
1639

    
1640
	$interval = $dpinger_default['interval'];
1641
	if ($gateway_settings['interval']) {
1642
		if (!is_numeric($gateway_settings['interval'])) {
1643
			$input_errors[] = gettext("The probe interval needs to be a numeric value.");
1644
		} else if ($gateway_settings['interval'] < 1) {
1645
			$input_errors[] = gettext("The probe interval needs to be positive.");
1646
		} else {
1647
			$interval = $gateway_settings['interval'];
1648
		}
1649
	}
1650

    
1651
	$loss_interval = $dpinger_default['loss_interval'];
1652
	if ($gateway_settings['loss_interval']) {
1653
		if (!is_numeric($gateway_settings['loss_interval'])) {
1654
			$input_errors[] = gettext("The loss interval needs to be a numeric value.");
1655
		} else if ($gateway_settings['loss_interval'] < 1) {
1656
			$input_errors[] = gettext("The loss interval setting needs to be positive.");
1657
		} else {
1658
			$loss_interval = $gateway_settings['loss_interval'];
1659
		}
1660
	}
1661

    
1662
	$alert_interval = $dpinger_default['alert_interval'];
1663
	if ($gateway_settings['alert_interval']) {
1664
		if (!is_numeric($gateway_settings['alert_interval'])) {
1665
			$input_errors[] = gettext("The alert interval needs to be a numeric value.");
1666
		} else if ($gateway_settings['alert_interval'] < 1) {
1667
			$input_errors[] = gettext("The alert interval setting needs to be positive.");
1668
		} else {
1669
			$alert_interval = $gateway_settings['alert_interval'];
1670
		}
1671
	}
1672

    
1673
	if ($latencylow >= $latencyhigh) {
1674
		$input_errors[] = gettext(
1675
		    "The high latency threshold needs to be greater than the low latency threshold");
1676
	}
1677

    
1678
	if ($losslow >= $losshigh) {
1679
		$input_errors[] = gettext(
1680
		    "The high packet loss threshold needs to be higher than the low packet loss threshold");
1681
	}
1682

    
1683
	// If the loss interval is less than latencyhigh, then high latency could never be recorded
1684
	// because those high latency packets would be considered as lost. So do not allow that.
1685
	if ($latencyhigh > $loss_interval) {
1686
		$input_errors[] = gettext("The loss interval needs to be greater than or equal to the high latency threshold.");
1687
	}
1688

    
1689
	// Ensure that the time period is greater than 2 times the probe interval plus the loss interval.
1690
	if (($interval * 2 + $loss_interval) >= $time_period) {
1691
		$input_errors[] = gettext("The time period needs to be greater than twice the probe interval plus the loss interval.");
1692
	}
1693

    
1694
	// There is no point recalculating the average latency and loss more often than the probe interval.
1695
	// So the alert interval needs to be >= probe interval.
1696
	if ($interval > $alert_interval) {
1697
		$input_errors[] = gettext("The alert interval needs to be greater than or equal to the probe interval.");
1698
	}
1699

    
1700
	return $input_errors;
1701
}
1702

    
1703
// Save gateway settings.
1704
// $gateway_settings - the array of gateway setting parameters
1705
// $realid - the index of the gateway to be modified (otherwise "" if adding a new gateway)
1706

    
1707
// This function is responsible to:
1708
//   Setup the gateway parameter structure from the gateway settings input parameter
1709
//   Save the structure into the config
1710
//   Remove any run-time settings from gateway parameters that are changed (e.g. remove routes to addresses that are changing)
1711

    
1712
// A subsequent "apply" step will implement the added/changed gateway.
1713

    
1714
function save_gateway($gateway_settings, $realid = "") {
1715
	global $config;
1716

    
1717
	$a_gateway_item = &$config['gateways']['gateway_item'];
1718
	$reloadif = "";
1719
	$gateway = array();
1720

    
1721
	if (empty($gateway_settings['interface'])) {
1722
		$gateway['interface'] = $gateway_settings['friendlyiface'];
1723
	} else {
1724
		$gateway['interface'] = $gateway_settings['interface'];
1725
	}
1726
	if (is_ipaddr($gateway_settings['gateway'])) {
1727
		$gateway['gateway'] = $gateway_settings['gateway'];
1728
	} else {
1729
		$gateway['gateway'] = "dynamic";
1730
	}
1731
	$gateway['name'] = $gateway_settings['name'];
1732
	$gateway['weight'] = $gateway_settings['weight'];
1733
	$gateway['ipprotocol'] = $gateway_settings['ipprotocol'];
1734
	if ($gateway_settings['interval']) {
1735
		$gateway['interval'] = $gateway_settings['interval'];
1736
	}
1737

    
1738
	if ($gateway_settings['time_period']) {
1739
		$gateway['time_period'] = $gateway_settings['time_period'];
1740
	}
1741
	if ($gateway_settings['alert_interval']) {
1742
		$gateway['alert_interval'] = $gateway_settings['alert_interval'];
1743
	}
1744

    
1745
	$gateway['descr'] = $gateway_settings['descr'];
1746
	if ($gateway_settings['monitor_disable'] == "yes") {
1747
		$gateway['monitor_disable'] = true;
1748
	}
1749
	if ($gateway_settings['action_disable'] == "yes") {
1750
		$gateway['action_disable'] = true;
1751
	}
1752
	if ($gateway_settings['nonlocalgateway'] == "yes") {
1753
		$gateway['nonlocalgateway'] = true;
1754
	}
1755
	if ($gateway_settings['force_down'] == "yes") {
1756
		$gateway['force_down'] = true;
1757
	}
1758
	if (is_ipaddr($gateway_settings['monitor'])) {
1759
		$gateway['monitor'] = $gateway_settings['monitor'];
1760
	}
1761
	if (isset($gateway_settings['data_payload']) && $gateway_settings['data_payload'] > 0) {
1762
		$gateway['data_payload'] = $gateway_settings['data_payload'];
1763
	}
1764

    
1765
	/* NOTE: If gateway ip is changed need to cleanup the old static interface route */
1766
	if ($gateway_settings['monitor'] != "dynamic" && !empty($a_gateway_item[$realid]) && is_ipaddr($a_gateway_item[$realid]['gateway']) &&
1767
		$gateway['gateway'] != $a_gateway_item[$realid]['gateway'] &&
1768
		isset($a_gateway_item[$realid]["nonlocalgateway"])) {
1769
		$realif = get_real_interface($a_gateway_item[$realid]['interface']);
1770
		$inet = (!is_ipaddrv4($a_gateway_item[$realid]['gateway']) ? "-inet6" : "-inet");
1771
		$cmd = "/sbin/route delete $inet " . escapeshellarg($a_gateway_item[$realid]['gateway']) . " -iface " . escapeshellarg($realif);
1772
		mwexec($cmd);
1773
	}
1774

    
1775
	/* NOTE: If monitor ip is changed need to cleanup the old static route */
1776
	if ($gateway_settings['monitor'] != "dynamic" && !empty($a_gateway_item[$realid]) && is_ipaddr($a_gateway_item[$realid]['monitor']) &&
1777
		$gateway_settings['monitor'] != $a_gateway_item[$realid]['monitor'] && $gateway['gateway'] != $a_gateway_item[$realid]['monitor']) {
1778
		if (is_ipaddrv4($a_gateway_item[$realid]['monitor'])) {
1779
			mwexec("/sbin/route delete " . escapeshellarg($a_gateway_item[$realid]['monitor']));
1780
		} else {
1781
			mwexec("/sbin/route delete -inet6 " . escapeshellarg($a_gateway_item[$realid]['monitor']));
1782
		}
1783
	}
1784

    
1785
	if ($gateway_settings['defaultgw'] == "yes" || $gateway_settings['defaultgw'] == "on") {
1786
		$i = 0;
1787
		/* remove the default gateway bits for all gateways with the same address family */
1788
		if (is_array($a_gateway_item)) {
1789
			foreach ($a_gateway_item as $gw) {
1790
				if ($gateway['ipprotocol'] == $gw['ipprotocol']) {
1791
					unset($config['gateways']['gateway_item'][$i]['defaultgw']);
1792
					if ($gw['interface'] != $gateway_settings['interface'] && $gw['defaultgw']) {
1793
						$reloadif = $gw['interface'];
1794
					}
1795
				}
1796
				$i++;
1797
			}
1798
		}
1799
		$gateway['defaultgw'] = true;
1800
	}
1801

    
1802
	if ($gateway_settings['latencylow']) {
1803
		$gateway['latencylow'] = $gateway_settings['latencylow'];
1804
	}
1805
	if ($gateway_settings['latencyhigh']) {
1806
		$gateway['latencyhigh'] = $gateway_settings['latencyhigh'];
1807
	}
1808
	if ($gateway_settings['losslow']) {
1809
		$gateway['losslow'] = $gateway_settings['losslow'];
1810
	}
1811
	if ($gateway_settings['losshigh']) {
1812
		$gateway['losshigh'] = $gateway_settings['losshigh'];
1813
	}
1814
	if ($gateway_settings['loss_interval']) {
1815
		$gateway['loss_interval'] = $gateway_settings['loss_interval'];
1816
	}
1817

    
1818
	if (isset($gateway_settings['disabled'])) {
1819
		$gateway['disabled'] = true;
1820
		/* Check if the gateway was enabled but changed to disabled. */
1821
		if ((isset($realid) && $a_gateway_item[$realid]) && ($a_gateway_item[$realid]['disabled'] == false)) {
1822
			/*  If the disabled gateway was the default route, remove the default route */
1823
			if (is_ipaddr($gateway['gateway']) &&
1824
				isset($gateway['defaultgw'])) {
1825
				$inet = (!is_ipaddrv4($gateway['gateway']) ? '-inet6' : '-inet');
1826
				mwexec("/sbin/route delete {$inet} default");
1827
			}
1828
		}
1829
	} else {
1830
		unset($gateway['disabled']);
1831
	}
1832

    
1833
	/* when saving the manual gateway we use the attribute which has the corresponding id */
1834
	if (isset($realid) && $a_gateway_item[$realid]) {
1835
		$a_gateway_item[$realid] = $gateway;
1836
	} else {
1837
		$a_gateway_item[] = $gateway;
1838
	}
1839

    
1840
	mark_subsystem_dirty('staticroutes');
1841

    
1842
	write_config();
1843

    
1844
	if (!empty($reloadif)) {
1845
		send_event("interface reconfigure {$reloadif}");
1846
	}
1847
}
1848
?>
(19-19/55)