Project

General

Profile

Download (11.8 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
    }
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

    
162
function relayd_configure() {
163
  global $config, $g;
164

    
165
  $vs_a = $config['load_balancer']['virtual_server'];
166
  $pool_a = $config['load_balancer']['lbpool'];
167
  $protocol_a = $config['load_balancer']['lbprotocol'];
168

    
169
  $check_a = array();
170

    
171
  foreach ((array)$config['load_balancer']['monitor_type'] as $type) {
172
    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
    if($mon) {
195
      $check_a[$type['name']] = $mon->p();
196
    }
197
  }
198

    
199

    
200
  $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
  $conf .= "log updates \n";
205
  $conf .= "timeout 1000 \n";
206
  /* 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
	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
        $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
//  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
	if(is_array($vs_a)) {
243
		for ($i = 0; isset($vs_a[$i]); $i++) {
244
			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
					$conf .= "  protocol \"{$vs_a[$i]['relay_protocol']}\"\n";
252
				}
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
			}
277
		}
278
	}
279
	fwrite($fd, $conf);
280
	fclose($fd);
281

    
282
	if (is_process_running('relayd')) {
283
		if (! empty($vs_a)) {
284
			// it's running and there is a config, just reload
285
			mwexec("/usr/local/sbin/relayctl reload");
286
		} else {
287
			/*
288
			 * XXX: Something breaks our control connection with relayd
289
			 * and makes 'relayctl stop' not work
290
			 * rule reloads are the current suspect
291
			 * mwexec('/usr/local/sbin/relayctl stop');
292
			 *  returns "command failed"
293
			 */
294
			mwexec('pkill relayd');
295
		}
296
	} else {
297
		if (! empty($vs_a)) {
298
			// not running and there is a config, start it
299
			mwexec("/usr/local/sbin/relayd -f {$g['varetc_path']}/relayd.conf");
300
		}
301
	}
302
}
303

    
304
function get_lb_redirects() {
305
/*
306
# relayctl show summary
307
Id   Type      Name                      Avlblty Status
308
1    redirect  testvs2                           active
309
5    table     test2:80                          active (3 hosts up)
310
11   host      192.168.1.2               91.55%  up
311
10   host      192.168.1.3               100.00% up
312
9    host      192.168.1.4               88.73%  up
313
3    table     test:80                           active (1 hosts up)
314
7    host      192.168.1.2               66.20%  down
315
6    host      192.168.1.3               97.18%  up
316
0    redirect  testvs                            active
317
3    table     test:80                           active (1 hosts up)
318
7    host      192.168.1.2               66.20%  down
319
6    host      192.168.1.3               97.18%  up
320
4    table     testvs-sitedown:80                active (1 hosts up)
321
8    host      192.168.1.4               84.51%  up
322
# relayctl show redirects
323
Id   Type      Name                      Avlblty Status
324
1    redirect  testvs2                           active
325
0    redirect  testvs                            active
326
# relayctl show redirects
327
Id   Type      Name                      Avlblty Status
328
1    redirect  testvs2                           active
329
           total: 2 sessions
330
           last: 2/60s 2/h 2/d sessions
331
           average: 1/60s 0/h 0/d sessions
332
0    redirect  testvs                            active
333
*/
334
	$rdr_a = array();
335
	exec('/usr/local/sbin/relayctl show redirects 2>&1', $rdr_a);
336
	$relay_a = array();
337
	exec('/usr/local/sbin/relayctl show relays 2>&1', $relay_a);
338
	$vs = array();
339
	for ($i = 0; isset($rdr_a[$i]); $i++) {
340
		$line = $rdr_a[$i];
341
		if (preg_match("/^[0-9]+/", $line)) {
342
			$regs = array();
343
			if($x = preg_match("/^[0-9]+\s+redirect\s+([^\s]+)\s+([^\s]+)/", $line, $regs)) {
344
				$vs[trim($regs[1])] = array();
345
				$vs[trim($regs[1])]['status'] = trim($regs[2]);
346
			}
347
		}
348
	}
349
	for ($i = 0; isset($relay_a[$i]); $i++) {
350
		$line = $relay_a[$i];
351
		if (preg_match("/^[0-9]+/", $line)) {
352
			$regs = array();
353
			if($x = preg_match("/^[0-9]+\s+relay\s+([^\s]+)\s+([^\s]+)/", $line, $regs)) {
354
				$vs[trim($regs[1])] = array();
355
				$vs[trim($regs[1])]['status'] = trim($regs[2]);
356
			}
357
		}
358
	}
359
	return $vs;
360
}
361

    
362
function get_lb_summary() {
363
	$relayctl = array();
364
	exec('/usr/local/sbin/relayctl show summary 2>&1', $relayctl);
365
	$relay_hosts=Array();
366
	foreach( (array) $relayctl as $line) {
367
		$t=split("\t", $line);
368
		switch (trim($t[1])) {
369
			case "table":
370
				$curpool=trim($t[2]);
371
			break;
372
			case "host":
373
				$curhost=trim($t[2]);
374
				$relay_hosts[$curpool][$curhost]['avail']=trim($t[3]);
375
				$relay_hosts[$curpool][$curhost]['state']=trim($t[4]);
376
			break;
377
		}
378
	}
379
	return $relay_hosts;
380
}
381

    
382
?>
(53-53/61)