Project

General

Profile

Download (12.9 KB) Statistics
| Branch: | Tag: | Revision:
1 3ad6d3bb Bill Marquette
<?php
2 577c9191 Bill Marquette
/* $Id$ */
3 3ad6d3bb Bill Marquette
/*
4 17623ab5 Bill Marquette
  vslb.inc
5
  Copyright (C) 2005-2008 Bill Marquette
6
  All rights reserved.
7 3ad6d3bb Bill Marquette
8 17623ab5 Bill Marquette
  Redistribution and use in source and binary forms, with or without
9
  modification, are permitted provided that the following conditions are met:
10 3ad6d3bb Bill Marquette
11 17623ab5 Bill Marquette
  1. Redistributions of source code must retain the above copyright notice,
12
  this list of conditions and the following disclaimer.
13 3ad6d3bb Bill Marquette
14 17623ab5 Bill Marquette
  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 3ad6d3bb Bill Marquette
18 17623ab5 Bill Marquette
  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 3ad6d3bb Bill Marquette
29 17623ab5 Bill Marquette
 */
30 3ad6d3bb Bill Marquette
31 523855b0 Scott Ullrich
/*
32
	pfSense_BUILDER_BINARIES:	/usr/local/sbin/relayd
33
	pfSense_MODULE:	routing
34
*/
35
36 50d86c13 Bill Marquette
/* DISABLE_PHP_LINT_CHECKING */
37
38 3ad6d3bb Bill Marquette
/* include all configuration functions */
39
40 50d86c13 Bill Marquette
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 0919224f Bill Marquette
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
    }
138
    case 'change': {
139
      $ret .= " \"{$actions_a[$action]['options']['akey']}\" to \"{$actions_a[$action]['options']['value']}\"";
140
      break;
141
    }
142
    case 'expect': {
143
      $ret .= " \"{$actions_a[$action]['options']['value']}\" from \"{$actions_a[$action]['options']['akey']}\"";
144
      break;
145
    }
146
    case 'filter': {
147
      $ret .= " \"{$actions_a[$action]['options']['value']}\" from \"{$actions_a[$action]['options']['akey']}\"";
148
      break;
149
    }
150
    case 'hash': {
151
      $ret .= " \"{$actions_a[$action]['options']['akey']}\"";
152
      break;
153
    }
154
    case 'log': {
155
      $ret .= " \"{$actions_a[$action]['options']['akey']}\"";
156
      break;
157
    }
158
  }
159
  return $ret;
160
}
161 50d86c13 Bill Marquette
162 d3534235 jim-p
function relayd_configure($kill_first=false) {
163 17623ab5 Bill Marquette
  global $config, $g;
164
165 a825c6f7 Bill Marquette
  $vs_a = $config['load_balancer']['virtual_server'];
166
  $pool_a = $config['load_balancer']['lbpool'];
167
  $protocol_a = $config['load_balancer']['lbprotocol'];
168 17623ab5 Bill Marquette
169 50d86c13 Bill Marquette
  $check_a = array();
170
171 52bd375c Bill Marquette
  foreach ((array)$config['load_balancer']['monitor_type'] as $type) {
172 50d86c13 Bill Marquette
    switch($type['type']) {
173
      case 'icmp': {
174
        $mon = new ICMPMonitor($type['options']);
175
	break;
176
      }
177
      case 'tcp': {
178
        $mon = new TCPMonitor($type['options']);
179
	break;
180
      }
181
      case 'http': {
182
        $mon = new HTTPMonitor($type['options']);
183
	break;
184
      }
185
      case 'https': {
186
        $mon = new HTTPSMonitor($type['options']);
187
	break;
188
      }
189
      case 'send': {
190
        $mon = new SendMonitor($type['options']);
191
	break;
192
      }
193
    }
194 596a3aba Seth Mos
    if($mon) {
195
      $check_a[$type['name']] = $mon->p();
196
    }
197 50d86c13 Bill Marquette
  }
198
199
200 17623ab5 Bill Marquette
  $fd = fopen("{$g['varetc_path']}/relayd.conf", "w");
201
202
  /* reindex pools by name as we loop through the pools array */
203
  $pools = array();
204 087a89f8 Chris Buechler
  $conf .= "log updates \n";
205 4a916dc8 Warren Baker
  $conf .= "timeout 1000 \n";
206 17623ab5 Bill Marquette
  /* Virtual server pools */
207
  if(is_array($pool_a)) {
208
    for ($i = 0; isset($pool_a[$i]); $i++) {
209
      if(is_array($pool_a[$i]['servers'])) {
210 74b7361f jim-p
	if (!empty($pool_a[$i]['retry'])) {
211
		$retrytext = " retry {$pool_a[$i]['retry']}";
212
		$srvtxt = implode("{$retrytext}, ", $pool_a[$i]['servers']) . "{$retrytext}";
213
	} else {
214
		$srvtxt = implode(", ", $pool_a[$i]['servers']);
215
	}
216 17623ab5 Bill Marquette
        $conf .= "table <{$pool_a[$i]['name']}> { $srvtxt }\n";
217
        /* Index by name for easier fetching when we loop through the virtual servers */
218
        $pools[$pool_a[$i]['name']] = $pool_a[$i];
219
      }
220
    }
221
  }
222 b6d74873 jim-p
//  if(is_array($protocol_a)) {
223
//    for ($i = 0; isset($protocol_a[$i]); $i++) {
224
//      $proto = "{$protocol_a[$i]['type']} protocol \"{$protocol_a[$i]['name']}\" {\n";
225
//      if(is_array($protocol_a[$i]['lbaction'])) {
226
//        if($protocol_a[$i]['lbaction'][0] == "") {
227
//          continue;
228
//        }
229
//        for ($a = 0; isset($protocol_a[$i]['lbaction'][$a]); $a++) {
230
//          $proto .= "  " . echo_lbaction($protocol_a[$i]['lbaction'][$a]) . "\n";
231
//        }
232
//      }
233
//      $proto .= "}\n";
234
//      $conf .= $proto;
235
//    }
236
//  }
237
238
	$conf .= "dns protocol \"dnsproto\" {\n";
239
	$conf .= "	tcp { nodelay, sack, socket buffer 1024, backlog 1000 }\n";
240
	$conf .= "}\n";
241
242 327ef8eb Warren Baker
	if(is_array($vs_a)) {
243 0130b756 Warren Baker
		for ($i = 0; isset($vs_a[$i]); $i++) {
244 b6d74873 jim-p
			if (($vs_a[$i]['mode'] == 'relay') || ($vs_a[$i]['relay_protocol'] == 'dns')) {
245
				$conf .= "relay \"{$vs_a[$i]['name']}\" {\n";
246
				$conf .= "  listen on {$vs_a[$i]['ipaddr']} port {$vs_a[$i]['port']}\n";
247
248
				if ($vs_a[$i]['relay_protocol'] == "dns") {
249
					$conf .= "  protocol \"dnsproto\"\n";
250
				} else {
251 d30afa60 jim-p
					$conf .= "  protocol \"{$vs_a[$i]['relay_protocol']}\"\n";
252 b6d74873 jim-p
				}
253
				$lbmode = "";
254
				if ( $pools[$vs_a[$i]['pool']]['mode'] == "loadbalance" ) {
255
					$lbmode = "mode loadbalance";
256
				}
257
258
				$conf .= "  forward to <{$vs_a[$i]['pool']}> port {$pools[$vs_a[$i]['pool']]['port']} {$lbmode} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
259
260
				if (isset($vs_a[$i]['sitedown']) &&  strlen($vs_a[$i]['sitedown']) > 0)
261
					$conf .= "  forward to <{$vs_a[$i]['sitedown']}> port {$pools[$vs_a[$i]['pool']]['port']} {$lbmode} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
262
				$conf .= "}\n";
263
			} else  {
264
				$conf .= "redirect \"{$vs_a[$i]['name']}\" {\n";
265
				$conf .= "  listen on {$vs_a[$i]['ipaddr']} port {$vs_a[$i]['port']}\n";
266
				$conf .= "  forward to <{$vs_a[$i]['pool']}> port {$pools[$vs_a[$i]['pool']]['port']} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
267
268
				if (isset($config['system']['lb_use_sticky']))
269
					$conf .= "  sticky-address\n";
270
271
				# sitedown MUST use the same port as the primary pool - sucks, but it's a relayd thing
272
				if (isset($vs_a[$i]['sitedown']) && strlen($vs_a[$i]['sitedown']) > 0)
273
					$conf .= "  forward to <{$vs_a[$i]['sitedown']}> port {$pools[$vs_a[$i]['pool']]['port']} {$check_a[$pools[$vs_a[$i]['pool']]['monitor']]} \n";
274
275
				$conf .= "}\n";
276 0130b756 Warren Baker
			}
277
		}
278
	}
279
	fwrite($fd, $conf);
280
	fclose($fd);
281
282
	if (is_process_running('relayd')) {
283
		if (! empty($vs_a)) {
284 d3534235 jim-p
			if ($kill_first) {
285
				mwexec('pkill relayd');
286
				mwexec("/usr/local/sbin/relayd -f {$g['varetc_path']}/relayd.conf");
287
			} else {
288
				// it's running and there is a config, just reload
289
				mwexec("/usr/local/sbin/relayctl reload");
290
			}
291 0130b756 Warren Baker
		} else {
292
			/*
293
			 * XXX: Something breaks our control connection with relayd
294
			 * and makes 'relayctl stop' not work
295
			 * rule reloads are the current suspect
296
			 * mwexec('/usr/local/sbin/relayctl stop');
297
			 *  returns "command failed"
298
			 */
299
			mwexec('pkill relayd');
300
		}
301 b1bd2119 Chris Buechler
	} else {
302 0130b756 Warren Baker
		if (! empty($vs_a)) {
303
			// not running and there is a config, start it
304
			mwexec("/usr/local/sbin/relayd -f {$g['varetc_path']}/relayd.conf");
305
		}
306 b1bd2119 Chris Buechler
	}
307 3ad6d3bb Bill Marquette
}
308
309 a776c720 jim-p
function get_lb_redirects() {
310
/*
311
# relayctl show summary
312
Id   Type      Name                      Avlblty Status
313
1    redirect  testvs2                           active
314
5    table     test2:80                          active (3 hosts up)
315
11   host      192.168.1.2               91.55%  up
316
10   host      192.168.1.3               100.00% up
317
9    host      192.168.1.4               88.73%  up
318
3    table     test:80                           active (1 hosts up)
319
7    host      192.168.1.2               66.20%  down
320
6    host      192.168.1.3               97.18%  up
321
0    redirect  testvs                            active
322
3    table     test:80                           active (1 hosts up)
323
7    host      192.168.1.2               66.20%  down
324
6    host      192.168.1.3               97.18%  up
325
4    table     testvs-sitedown:80                active (1 hosts up)
326
8    host      192.168.1.4               84.51%  up
327
# relayctl show redirects
328
Id   Type      Name                      Avlblty Status
329
1    redirect  testvs2                           active
330
0    redirect  testvs                            active
331
# relayctl show redirects
332
Id   Type      Name                      Avlblty Status
333
1    redirect  testvs2                           active
334
           total: 2 sessions
335
           last: 2/60s 2/h 2/d sessions
336
           average: 1/60s 0/h 0/d sessions
337
0    redirect  testvs                            active
338
*/
339
	$rdr_a = array();
340
	exec('/usr/local/sbin/relayctl show redirects 2>&1', $rdr_a);
341 b6d74873 jim-p
	$relay_a = array();
342
	exec('/usr/local/sbin/relayctl show relays 2>&1', $relay_a);
343 a776c720 jim-p
	$vs = array();
344 ff160984 jim-p
	$cur_entry = "";
345 a776c720 jim-p
	for ($i = 0; isset($rdr_a[$i]); $i++) {
346
		$line = $rdr_a[$i];
347
		if (preg_match("/^[0-9]+/", $line)) {
348
			$regs = array();
349
			if($x = preg_match("/^[0-9]+\s+redirect\s+([^\s]+)\s+([^\s]+)/", $line, $regs)) {
350 ff160984 jim-p
				$cur_entry = trim($regs[1]);
351 a776c720 jim-p
				$vs[trim($regs[1])] = array();
352
				$vs[trim($regs[1])]['status'] = trim($regs[2]);
353
			}
354 ff160984 jim-p
		} elseif (($x = preg_match("/^\s+total:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
355
			$vs[$cur_entry]['total'] = trim($regs[1]);
356
		} elseif (($x = preg_match("/^\s+last:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
357
			$vs[$cur_entry]['last'] = trim($regs[1]);
358
		} elseif (($x = preg_match("/^\s+average:(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
359
			$vs[$cur_entry]['average'] = trim($regs[1]);
360 a776c720 jim-p
		}
361
	}
362 ff160984 jim-p
	$cur_entry = "";
363 b6d74873 jim-p
	for ($i = 0; isset($relay_a[$i]); $i++) {
364
		$line = $relay_a[$i];
365
		if (preg_match("/^[0-9]+/", $line)) {
366
			$regs = array();
367
			if($x = preg_match("/^[0-9]+\s+relay\s+([^\s]+)\s+([^\s]+)/", $line, $regs)) {
368 ff160984 jim-p
				$cur_entry = trim($regs[1]);
369 b6d74873 jim-p
				$vs[trim($regs[1])] = array();
370
				$vs[trim($regs[1])]['status'] = trim($regs[2]);
371
			}
372 ff160984 jim-p
		} elseif (($x = preg_match("/^\s+total:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
373
			$vs[$cur_entry]['total'] = trim($regs[1]);
374
		} elseif (($x = preg_match("/^\s+last:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
375
			$vs[$cur_entry]['last'] = trim($regs[1]);
376
		} elseif (($x = preg_match("/^\s+average:(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
377
			$vs[$cur_entry]['average'] = trim($regs[1]);
378 b6d74873 jim-p
		}
379
	}
380 a776c720 jim-p
	return $vs;
381
}
382
383
function get_lb_summary() {
384
	$relayctl = array();
385
	exec('/usr/local/sbin/relayctl show summary 2>&1', $relayctl);
386
	$relay_hosts=Array();
387
	foreach( (array) $relayctl as $line) {
388
		$t=split("\t", $line);
389
		switch (trim($t[1])) {
390
			case "table":
391
				$curpool=trim($t[2]);
392
			break;
393
			case "host":
394
				$curhost=trim($t[2]);
395
				$relay_hosts[$curpool][$curhost]['avail']=trim($t[3]);
396
				$relay_hosts[$curpool][$curhost]['state']=trim($t[4]);
397
			break;
398
		}
399
	}
400
	return $relay_hosts;
401
}
402
403 9b0ddd8c Ermal
?>