Project

General

Profile

Download (13.3 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
	$vs_a = $config['load_balancer']['virtual_server'];
160
	$pool_a = $config['load_balancer']['lbpool'];
161
	$protocol_a = $config['load_balancer']['lbprotocol'];
162
	$setting = $config['load_balancer']['setting'];
163

    
164
	$check_a = array();
165

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

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

    
246
	$conf .= "dns protocol \"dnsproto\" {\n";
247
	$conf .= "\ttcp { nodelay, sack, socket buffer 1024, backlog 1000 }\n";
248
	$conf .= "}\n";
249

    
250
	if(is_array($vs_a)) {
251
		for ($i = 0; isset($vs_a[$i]); $i++) {
252
			if (($vs_a[$i]['mode'] == 'relay') || ($vs_a[$i]['relay_protocol'] == 'dns')) {
253
				$conf .= "relay \"{$vs_a[$i]['name']}\" {\n";
254
				$conf .= "  listen on {$vs_a[$i]['ipaddr']} port {$vs_a[$i]['port']}\n";
255

    
256
				if ($vs_a[$i]['relay_protocol'] == "dns") {
257
					$conf .= "  protocol \"dnsproto\"\n";
258
				} else {
259
					$conf .= "  protocol \"{$vs_a[$i]['relay_protocol']}\"\n";
260
				}
261
				$lbmode = "";
262
				if ( $pools[$vs_a[$i]['pool']]['mode'] == "loadbalance" ) {
263
					$lbmode = "mode loadbalance";
264
				}
265

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

    
268
				if (isset($vs_a[$i]['sitedown']) &&  strlen($vs_a[$i]['sitedown']) > 0)
269
					$conf .= "  forward to <{$vs_a[$i]['sitedown']}> port {$pools[$vs_a[$i]['pool']]['port']} {$lbmode} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
270
				$conf .= "}\n";
271
			} else  {
272
				$conf .= "redirect \"{$vs_a[$i]['name']}\" {\n";
273
				$conf .= "  listen on {$vs_a[$i]['ipaddr']} port {$vs_a[$i]['port']}\n";
274
				$conf .= "  forward to <{$vs_a[$i]['pool']}> port {$pools[$vs_a[$i]['pool']]['port']} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
275

    
276
				if (isset($config['system']['lb_use_sticky']))
277
					$conf .= "  sticky-address\n";
278

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

    
283
				$conf .= "}\n";
284
			}
285
		}
286
	}
287
	fwrite($fd, $conf);
288
	fclose($fd);
289

    
290
	if (is_process_running('relayd')) {
291
		if (! empty($vs_a)) {
292
			if ($kill_first) {
293
				mwexec('pkill relayd');
294
				mwexec("/usr/local/sbin/relayd -f {$g['varetc_path']}/relayd.conf");
295
			} else {
296
				// it's running and there is a config, just reload
297
				mwexec("/usr/local/sbin/relayctl reload");
298
			}
299
		} else {
300
			/*
301
			 * XXX: Something breaks our control connection with relayd
302
			 * and makes 'relayctl stop' not work
303
			 * rule reloads are the current suspect
304
			 * mwexec('/usr/local/sbin/relayctl stop');
305
			 *  returns "command failed"
306
			 */
307
			mwexec('pkill relayd');
308
		}
309
	} else {
310
		if (! empty($vs_a)) {
311
			// not running and there is a config, start it
312
			mwexec("/usr/local/sbin/relayd -f {$g['varetc_path']}/relayd.conf");
313
		}
314
	}
315
}
316

    
317
function get_lb_redirects() {
318
/*
319
# relayctl show summary
320
Id   Type      Name                      Avlblty Status
321
1    redirect  testvs2                           active
322
5    table     test2:80                          active (3 hosts up)
323
11   host      192.168.1.2               91.55%  up
324
10   host      192.168.1.3               100.00% up
325
9    host      192.168.1.4               88.73%  up
326
3    table     test:80                           active (1 hosts up)
327
7    host      192.168.1.2               66.20%  down
328
6    host      192.168.1.3               97.18%  up
329
0    redirect  testvs                            active
330
3    table     test:80                           active (1 hosts up)
331
7    host      192.168.1.2               66.20%  down
332
6    host      192.168.1.3               97.18%  up
333
4    table     testvs-sitedown:80                active (1 hosts up)
334
8    host      192.168.1.4               84.51%  up
335
# relayctl show redirects
336
Id   Type      Name                      Avlblty Status
337
1    redirect  testvs2                           active
338
0    redirect  testvs                            active
339
# relayctl show redirects
340
Id   Type      Name                      Avlblty Status
341
1    redirect  testvs2                           active
342
           total: 2 sessions
343
           last: 2/60s 2/h 2/d sessions
344
           average: 1/60s 0/h 0/d sessions
345
0    redirect  testvs                            active
346
*/
347
	$rdr_a = array();
348
	exec('/usr/local/sbin/relayctl show redirects 2>&1', $rdr_a);
349
	$relay_a = array();
350
	exec('/usr/local/sbin/relayctl show relays 2>&1', $relay_a);
351
	$vs = array();
352
	$cur_entry = "";
353
	for ($i = 0; isset($rdr_a[$i]); $i++) {
354
		$line = $rdr_a[$i];
355
		if (preg_match("/^[0-9]+/", $line)) {
356
			$regs = array();
357
			if($x = preg_match("/^[0-9]+\s+redirect\s+([^\s]+)\s+([^\s]+)/", $line, $regs)) {
358
				$cur_entry = trim($regs[1]);
359
				$vs[trim($regs[1])] = array();
360
				$vs[trim($regs[1])]['status'] = trim($regs[2]);
361
			}
362
		} elseif (($x = preg_match("/^\s+total:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
363
			$vs[$cur_entry]['total'] = trim($regs[1]);
364
		} elseif (($x = preg_match("/^\s+last:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
365
			$vs[$cur_entry]['last'] = trim($regs[1]);
366
		} elseif (($x = preg_match("/^\s+average:(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
367
			$vs[$cur_entry]['average'] = trim($regs[1]);
368
		}
369
	}
370
	$cur_entry = "";
371
	for ($i = 0; isset($relay_a[$i]); $i++) {
372
		$line = $relay_a[$i];
373
		if (preg_match("/^[0-9]+/", $line)) {
374
			$regs = array();
375
			if($x = preg_match("/^[0-9]+\s+relay\s+([^\s]+)\s+([^\s]+)/", $line, $regs)) {
376
				$cur_entry = trim($regs[1]);
377
				$vs[trim($regs[1])] = array();
378
				$vs[trim($regs[1])]['status'] = trim($regs[2]);
379
			}
380
		} elseif (($x = preg_match("/^\s+total:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
381
			$vs[$cur_entry]['total'] = trim($regs[1]);
382
		} elseif (($x = preg_match("/^\s+last:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
383
			$vs[$cur_entry]['last'] = trim($regs[1]);
384
		} elseif (($x = preg_match("/^\s+average:(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
385
			$vs[$cur_entry]['average'] = trim($regs[1]);
386
		}
387
	}
388
	return $vs;
389
}
390

    
391
function get_lb_summary() {
392
	$relayctl = array();
393
	exec('/usr/local/sbin/relayctl show summary 2>&1', $relayctl);
394
	$relay_hosts=Array();
395
	foreach( (array) $relayctl as $line) {
396
		$t = explode("\t", $line);
397
		switch (trim($t[1])) {
398
			case "table":
399
				$curpool=trim($t[2]);
400
				break;
401
			case "host":
402
				$curhost=trim($t[2]);
403
				$relay_hosts[$curpool][$curhost]['avail']=trim($t[3]);
404
				$relay_hosts[$curpool][$curhost]['state']=trim($t[4]);
405
				break;
406
		}
407
	}
408
	return $relay_hosts;
409
}
410

    
411
?>
(57-57/65)