Project

General

Profile

Download (14.5 KB) Statistics
| Branch: | Tag: | Revision:
1
<?php
2
/* $Id$ */
3
/*
4
  vslb.inc
5
  Copyright (C) 2005-2008 Bill Marquette
6
  All rights reserved.
7

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

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

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

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

    
29
 */
30

    
31
/*
32
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/relayd
33
	pfSense_MODULE:	routing
34
*/
35

    
36
/* DISABLE_PHP_LINT_CHECKING */
37

    
38
/* include all configuration functions */
39

    
40
class Monitor {
41
	private $conf = array();
42
	function __construct($config) {
43
		$this->conf = $config;
44
	}
45

    
46
	public function p() {
47
		return "check {$this->get('proto')}";
48
	}
49
	private function get($var) {
50
		return isset($this->$var) ? $this->$var : "";
51
	}
52
	protected function config($element) {
53
		return isset($this->conf[$element]) ? $this->conf[$element] : "";
54
	}
55
}
56

    
57
class TCPMonitor extends Monitor {
58
	protected $proto = 'tcp';
59
}
60

    
61
class SSLMonitor extends Monitor {
62
	protected $proto = 'ssl';
63
}
64

    
65
class ICMPMonitor extends Monitor {
66
	protected $proto = 'icmp';
67
}
68

    
69
class HTTPMonitor extends Monitor {
70
	protected $proto = 'http';
71
	function __construct($config) {
72
		parent::__construct($config);
73
	}
74
	public function p() {
75
		$method = ($this->code() != "") ? $this->code() : $this->digest();
76
		return "check {$this->proto} {$this->path()} {$this->host()} {$method}";
77
	}
78

    
79
	private function path() {
80
		return $this->config('path') != "" ? "'{$this->config('path')}'" : "";
81
	}
82

    
83
	private function host() {
84
		return $this->config('host') != "" ? "host {$this->config('host')}" : "";
85
	}
86

    
87
	private function code() {
88
		return $this->config('code') != "" ? "code {$this->config('code')}" : "";
89
	}
90

    
91
	private function digest() {
92
		return $this->config('digest') != "" ? "digest {$this->config('digest')}" : "";
93
	}
94
}
95

    
96
class HTTPSMonitor extends HTTPMonitor {
97
	protected $proto = 'https';
98
}
99

    
100
class SendMonitor extends Monitor {
101
	private $proto = 'send';
102
	function __construct($config) {
103
		parent::__construct($config);
104
	}
105
	public function p() {
106
		return "check {$this->proto} {$this->data()} expect {$this->pattern()} {$this->ssl()}";
107
	}
108

    
109

    
110
	private function data() {
111
		return $this->config('send') != "" ? "\"{$this->config('send')}\"" : "\"\"";
112
	}
113

    
114
	private function pattern() {
115
		return $this->config('expect') != "" ? "\"{$this->config('expect')}\"" : "\"\"";
116
	}
117

    
118
	private function ssl() {
119
		return $this->config('ssl') == true ? "ssl" : "";
120
	}
121
}
122

    
123
function echo_lbaction($action) {
124
	global $config;
125
  
126
	// Index actions by name
127
	$actions_a = array();
128
	for ($i=0; isset($config['load_balancer']['lbaction'][$i]); $i++)
129
		$actions_a[$config['load_balancer']['lbaction'][$i]['name']] = $config['load_balancer']['lbaction'][$i];
130

    
131
	$ret = "";
132
	$ret .=  "{$actions_a[$action]['direction']} {$actions_a[$action]['type']} {$actions_a[$action]['action']}";
133
	switch($actions_a[$action]['action']) {
134
	case 'append':
135
		$ret .= " \"{$actions_a[$action]['options']['value']}\" to \"{$actions_a[$action]['options']['akey']}\"";
136
		break;
137
	case 'change':
138
		$ret .= " \"{$actions_a[$action]['options']['akey']}\" to \"{$actions_a[$action]['options']['value']}\"";
139
		break;
140
	case 'expect':
141
		$ret .= " \"{$actions_a[$action]['options']['value']}\" from \"{$actions_a[$action]['options']['akey']}\"";
142
		break;
143
	case 'filter':
144
		$ret .= " \"{$actions_a[$action]['options']['value']}\" from \"{$actions_a[$action]['options']['akey']}\"";
145
		break;
146
	case 'hash':
147
		$ret .= " \"{$actions_a[$action]['options']['akey']}\"";
148
		break;
149
	case 'log':
150
		$ret .= " \"{$actions_a[$action]['options']['akey']}\"";
151
		break;
152
	}
153
	return $ret;
154
}
155

    
156
function relayd_configure($kill_first=false) {
157
	global $config, $g;
158

    
159
	require_once("filter.inc");
160

    
161
	$vs_a = $config['load_balancer']['virtual_server'];
162
	$pool_a = $config['load_balancer']['lbpool'];
163
	$protocol_a = $config['load_balancer']['lbprotocol'];
164
	$setting = $config['load_balancer']['setting'];
165

    
166
	$check_a = array();
167

    
168
	foreach ((array)$config['load_balancer']['monitor_type'] as $type) {
169
		switch($type['type']) {
170
		case 'icmp':
171
			$mon = new ICMPMonitor($type['options']);
172
			break;
173
		case 'tcp':
174
			$mon = new TCPMonitor($type['options']);
175
			break;
176
		case 'http':
177
			$mon = new HTTPMonitor($type['options']);
178
			break;
179
		case 'https':
180
			$mon = new HTTPSMonitor($type['options']);
181
			break;
182
		case 'send':
183
			$mon = new SendMonitor($type['options']);
184
			break;
185
		}
186
		if($mon) {
187
			$check_a[$type['name']] = $mon->p();
188
		}
189
	}
190
	
191
  
192
	$fd = fopen("{$g['varetc_path']}/relayd.conf", "w");
193
	$conf .= "log updates \n";
194

    
195
	/* Global timeout, interval and prefork settings
196
	   if not specified by the user:
197
	   - use a 1000 ms timeout value as in pfsense 2.0.1 and above
198
	   - leave interval and prefork empty, relayd will use its default values */
199
	
200
	if (isset($setting['timeout']) && !empty($setting['timeout'])) {
201
		$conf .= "timeout ".$setting['timeout']." \n";
202
	} else {
203
		$conf .= "timeout 1000 \n";
204
	}
205
	
206
	if (isset($setting['interval']) && !empty($setting['interval'])) {
207
		$conf .= "interval ".$setting['interval']." \n";
208
	}
209
	
210
	if (isset($setting['prefork']) && !empty($setting['prefork'])) {
211
		$conf .= "prefork ".$setting['prefork']." \n";
212
	}
213
	
214
	/* reindex pools by name as we loop through the pools array */
215
	$pools = array();
216
	/* Virtual server pools */
217
	if(is_array($pool_a)) {
218
		for ($i = 0; isset($pool_a[$i]); $i++) {
219
			if(is_array($pool_a[$i]['servers'])) {
220
				if (!empty($pool_a[$i]['retry'])) {
221
					$retrytext = " retry {$pool_a[$i]['retry']}";
222
				} else {
223
					$retrytext = "";
224
				}
225
				$conf .= "table <{$pool_a[$i]['name']}> {\n";
226
				foreach ($pool_a[$i]['servers'] as $server) {
227
					if (is_subnetv4($server)) {
228
						foreach (subnetv4_expand($server) as $ip) {
229
							$conf .= "\t{$ip}{$retrytext}\n";
230
						}
231
					}
232
					else {
233
						$conf .= "\t{$server}{$retrytext}\n";
234
					}
235
				}
236
				$conf .= "}\n";
237
				/* Index by name for easier fetching when we loop through the virtual servers */
238
				$pools[$pool_a[$i]['name']] = $pool_a[$i];
239
			}
240
		}
241
	}
242
//  if(is_array($protocol_a)) {
243
//    for ($i = 0; isset($protocol_a[$i]); $i++) {
244
//      $proto = "{$protocol_a[$i]['type']} protocol \"{$protocol_a[$i]['name']}\" {\n";
245
//      if(is_array($protocol_a[$i]['lbaction'])) {
246
//        if($protocol_a[$i]['lbaction'][0] == "") {
247
//          continue;
248
//        }
249
//        for ($a = 0; isset($protocol_a[$i]['lbaction'][$a]); $a++) {
250
//          $proto .= "  " . echo_lbaction($protocol_a[$i]['lbaction'][$a]) . "\n";
251
//        }
252
//      }
253
//      $proto .= "}\n";
254
//      $conf .= $proto;
255
//    }
256
//  }
257

    
258
	$conf .= "dns protocol \"dnsproto\" {\n";
259
	$conf .= "\t" . "tcp { nodelay, sack, socket buffer 1024, backlog 1000 }\n";
260
	$conf .= "}\n";
261

    
262
	if(is_array($vs_a)) {
263
		for ($i = 0; isset($vs_a[$i]); $i++) {
264
			
265
			$append_port_to_name = false;
266
			if (is_alias($vs_a[$i]['port'])) {
267
				$src_port_array = filter_expand_alias_array($vs_a[$i]['port']);
268
				$append_port_to_name = true;
269
			}
270
			else {
271
				$src_port_array = array($vs_a[$i]['port']);
272
			}
273
			if (is_alias($pools[$vs_a[$i]['pool']]['port'])) {
274
				$dest_port_array = filter_expand_alias_array($pools[$vs_a[$i]['pool']]['port']);
275
				$append_port_to_name = true;
276
			}
277
			else {
278
				$dest_port_array = array($pools[$vs_a[$i]['pool']]['port']);
279
			}
280

    
281
			$append_ip_to_name = false;
282
			if (is_subnetv4($vs_a[$i]['ipaddr'])) {
283
				$ip_list = subnetv4_expand($vs_a[$i]['ipaddr']);
284
				$append_ip_to_name = true;
285
			}
286
			else {
287
				$ip_list = array($vs_a[$i]['ipaddr']);
288
			}
289

    
290
			for ($j = 0; $j < count($ip_list); $j += 1) {
291
				$ip = $ip_list[$j];
292
				for ($k = 0; $k < count($src_port_array) && $k < count($dest_port_array); $k += 1) {
293
					$src_port  = $src_port_array[$k];
294
					$dest_port = $dest_port_array[$k];
295

    
296
					$name = $vs_a[$i]['name'];
297
					if ($append_ip_to_name) {
298
						$name .= "_" . $j;
299
					}
300
					if ($append_port_to_name) {
301
						$name .= "_" . $src_port;
302
					}
303

    
304
					if (($vs_a[$i]['mode'] == 'relay') || ($vs_a[$i]['relay_protocol'] == 'dns')) {
305
						$conf .= "relay \"{$name}\" {\n";
306
						$conf .= "  listen on {$ip} port {$src_port}\n";
307

    
308
						if ($vs_a[$i]['relay_protocol'] == "dns") {
309
							$conf .= "  protocol \"dnsproto\"\n";
310
						} else {
311
							$conf .= "  protocol \"{$vs_a[$i]['relay_protocol']}\"\n";
312
						}
313
						$lbmode = "";
314
						if ( $pools[$vs_a[$i]['pool']]['mode'] == "loadbalance" ) {
315
							$lbmode = "mode loadbalance";
316
						}
317

    
318
						$conf .= "  forward to <{$vs_a[$i]['pool']}> port {$dest_port} {$lbmode} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
319

    
320
						if (isset($vs_a[$i]['sitedown']) &&  strlen($vs_a[$i]['sitedown']) > 0)
321
							$conf .= "  forward to <{$vs_a[$i]['sitedown']}> port {$dest_port} {$lbmode} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
322
						$conf .= "}\n";
323
					} else  {
324
						$conf .= "redirect \"{$name}\" {\n";
325
						$conf .= "  listen on {$ip} port {$src_port}\n";
326
						$conf .= "  forward to <{$vs_a[$i]['pool']}> port {$dest_port} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
327

    
328
						if (isset($config['system']['lb_use_sticky']))
329
							$conf .= "  sticky-address\n";
330

    
331
						/* sitedown MUST use the same port as the primary pool - sucks, but it's a relayd thing */
332
						if (isset($vs_a[$i]['sitedown']) && strlen($vs_a[$i]['sitedown']) > 0)
333
							$conf .= "  forward to <{$vs_a[$i]['sitedown']}> port {$dest_port} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
334

    
335
						$conf .= "}\n";
336
					}
337
				}
338
			}
339
		}
340
	}
341
	fwrite($fd, $conf);
342
	fclose($fd);
343

    
344
	if (is_process_running('relayd')) {
345
		if (! empty($vs_a)) {
346
			if ($kill_first) {
347
				mwexec('pkill relayd');
348
				mwexec("/usr/local/sbin/relayd -f {$g['varetc_path']}/relayd.conf");
349
			} else {
350
				// it's running and there is a config, just reload
351
				mwexec("/usr/local/sbin/relayctl reload");
352
			}
353
		} else {
354
			/*
355
			 * XXX: Something breaks our control connection with relayd
356
			 * and makes 'relayctl stop' not work
357
			 * rule reloads are the current suspect
358
			 * mwexec('/usr/local/sbin/relayctl stop');
359
			 *  returns "command failed"
360
			 */
361
			mwexec('pkill relayd');
362
		}
363
	} else {
364
		if (! empty($vs_a)) {
365
			// not running and there is a config, start it
366
			mwexec("/usr/local/sbin/relayd -f {$g['varetc_path']}/relayd.conf");
367
		}
368
	}
369
}
370

    
371
function get_lb_redirects() {
372
/*
373
# relayctl show summary
374
Id   Type      Name                      Avlblty Status
375
1    redirect  testvs2                           active
376
5    table     test2:80                          active (3 hosts up)
377
11   host      192.168.1.2               91.55%  up
378
10   host      192.168.1.3               100.00% up
379
9    host      192.168.1.4               88.73%  up
380
3    table     test:80                           active (1 hosts up)
381
7    host      192.168.1.2               66.20%  down
382
6    host      192.168.1.3               97.18%  up
383
0    redirect  testvs                            active
384
3    table     test:80                           active (1 hosts up)
385
7    host      192.168.1.2               66.20%  down
386
6    host      192.168.1.3               97.18%  up
387
4    table     testvs-sitedown:80                active (1 hosts up)
388
8    host      192.168.1.4               84.51%  up
389
# relayctl show redirects
390
Id   Type      Name                      Avlblty Status
391
1    redirect  testvs2                           active
392
0    redirect  testvs                            active
393
# relayctl show redirects
394
Id   Type      Name                      Avlblty Status
395
1    redirect  testvs2                           active
396
           total: 2 sessions
397
           last: 2/60s 2/h 2/d sessions
398
           average: 1/60s 0/h 0/d sessions
399
0    redirect  testvs                            active
400
*/
401
	$rdr_a = array();
402
	exec('/usr/local/sbin/relayctl show redirects 2>&1', $rdr_a);
403
	$relay_a = array();
404
	exec('/usr/local/sbin/relayctl show relays 2>&1', $relay_a);
405
	$vs = array();
406
	$cur_entry = "";
407
	for ($i = 0; isset($rdr_a[$i]); $i++) {
408
		$line = $rdr_a[$i];
409
		if (preg_match("/^[0-9]+/", $line)) {
410
			$regs = array();
411
			if($x = preg_match("/^[0-9]+\s+redirect\s+([^\s]+)\s+([^\s]+)/", $line, $regs)) {
412
				$cur_entry = trim($regs[1]);
413
				$vs[trim($regs[1])] = array();
414
				$vs[trim($regs[1])]['status'] = trim($regs[2]);
415
			}
416
		} elseif (($x = preg_match("/^\s+total:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
417
			$vs[$cur_entry]['total'] = trim($regs[1]);
418
		} elseif (($x = preg_match("/^\s+last:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
419
			$vs[$cur_entry]['last'] = trim($regs[1]);
420
		} elseif (($x = preg_match("/^\s+average:(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
421
			$vs[$cur_entry]['average'] = trim($regs[1]);
422
		}
423
	}
424
	$cur_entry = "";
425
	for ($i = 0; isset($relay_a[$i]); $i++) {
426
		$line = $relay_a[$i];
427
		if (preg_match("/^[0-9]+/", $line)) {
428
			$regs = array();
429
			if($x = preg_match("/^[0-9]+\s+relay\s+([^\s]+)\s+([^\s]+)/", $line, $regs)) {
430
				$cur_entry = trim($regs[1]);
431
				$vs[trim($regs[1])] = array();
432
				$vs[trim($regs[1])]['status'] = trim($regs[2]);
433
			}
434
		} elseif (($x = preg_match("/^\s+total:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
435
			$vs[$cur_entry]['total'] = trim($regs[1]);
436
		} elseif (($x = preg_match("/^\s+last:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
437
			$vs[$cur_entry]['last'] = trim($regs[1]);
438
		} elseif (($x = preg_match("/^\s+average:(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
439
			$vs[$cur_entry]['average'] = trim($regs[1]);
440
		}
441
	}
442
	return $vs;
443
}
444

    
445
function get_lb_summary() {
446
	$relayctl = array();
447
	exec('/usr/local/sbin/relayctl show summary 2>&1', $relayctl);
448
	$relay_hosts=Array();
449
	foreach( (array) $relayctl as $line) {
450
		$t = explode("\t", $line);
451
		switch (trim($t[1])) {
452
			case "table":
453
				$curpool=trim($t[2]);
454
				break;
455
			case "host":
456
				$curhost=trim($t[2]);
457
				$relay_hosts[$curpool][$curhost]['avail']=trim($t[3]);
458
				$relay_hosts[$curpool][$curhost]['state']=trim($t[4]);
459
				break;
460
		}
461
	}
462
	return $relay_hosts;
463
}
464

    
465
?>
(57-57/65)