Project

General

Profile

Download (15.1 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 146a1717 jim-p
		return $this->config('send') != "" ? "\"{$this->config('send')}\"" : "\"\"";
112 50d86c13 Bill Marquette
	}
113
114
	private function pattern() {
115 146a1717 jim-p
		return $this->config('expect') != "" ? "\"{$this->config('expect')}\"" : "\"\"";
116 50d86c13 Bill Marquette
	}
117
118
	private function ssl() {
119
		return $this->config('ssl') == true ? "ssl" : "";
120
	}
121
}
122
123 0919224f Bill Marquette
function echo_lbaction($action) {
124 939b2d75 Darren Embry
	global $config;
125 0919224f Bill Marquette
  
126 939b2d75 Darren Embry
	// Index actions by name
127
	$actions_a = array();
128
	for ($i=0; isset($config['load_balancer']['lbaction'][$i]); $i++)
129 0919224f Bill Marquette
		$actions_a[$config['load_balancer']['lbaction'][$i]['name']] = $config['load_balancer']['lbaction'][$i];
130
131 939b2d75 Darren Embry
	$ret = "";
132
	$ret .=  "{$actions_a[$action]['direction']} {$actions_a[$action]['type']} {$actions_a[$action]['action']}";
133
	switch($actions_a[$action]['action']) {
134 9859b2b5 Darren Embry
	case 'append':
135 939b2d75 Darren Embry
		$ret .= " \"{$actions_a[$action]['options']['value']}\" to \"{$actions_a[$action]['options']['akey']}\"";
136
		break;
137 9859b2b5 Darren Embry
	case 'change':
138 939b2d75 Darren Embry
		$ret .= " \"{$actions_a[$action]['options']['akey']}\" to \"{$actions_a[$action]['options']['value']}\"";
139
		break;
140 9859b2b5 Darren Embry
	case 'expect':
141 939b2d75 Darren Embry
		$ret .= " \"{$actions_a[$action]['options']['value']}\" from \"{$actions_a[$action]['options']['akey']}\"";
142
		break;
143 9859b2b5 Darren Embry
	case 'filter':
144 939b2d75 Darren Embry
		$ret .= " \"{$actions_a[$action]['options']['value']}\" from \"{$actions_a[$action]['options']['akey']}\"";
145
		break;
146 9859b2b5 Darren Embry
	case 'hash':
147 939b2d75 Darren Embry
		$ret .= " \"{$actions_a[$action]['options']['akey']}\"";
148
		break;
149 9859b2b5 Darren Embry
	case 'log':
150 939b2d75 Darren Embry
		$ret .= " \"{$actions_a[$action]['options']['akey']}\"";
151
		break;
152
	}
153
	return $ret;
154 0919224f Bill Marquette
}
155 50d86c13 Bill Marquette
156 d3534235 jim-p
function relayd_configure($kill_first=false) {
157 939b2d75 Darren Embry
	global $config, $g;
158
159 f57a578d Darren Embry
	// have to do this until every call to filter.inc is
160
	// require_once() instead of require().
161 91b2f623 bcyrill
	if (!function_exists('filter_expand_alias_array')) {
162 f57a578d Darren Embry
		require_once("filter.inc");
163
	}
164 d7afd900 Darren Embry
165 939b2d75 Darren Embry
	$vs_a = $config['load_balancer']['virtual_server'];
166
	$pool_a = $config['load_balancer']['lbpool'];
167
	$protocol_a = $config['load_balancer']['lbprotocol'];
168
	$setting = $config['load_balancer']['setting'];
169
170
	$check_a = array();
171 50d86c13 Bill Marquette
172 939b2d75 Darren Embry
	foreach ((array)$config['load_balancer']['monitor_type'] as $type) {
173
		switch($type['type']) {
174 9859b2b5 Darren Embry
		case 'icmp':
175 939b2d75 Darren Embry
			$mon = new ICMPMonitor($type['options']);
176
			break;
177 9859b2b5 Darren Embry
		case 'tcp':
178 939b2d75 Darren Embry
			$mon = new TCPMonitor($type['options']);
179
			break;
180 9859b2b5 Darren Embry
		case 'http':
181 939b2d75 Darren Embry
			$mon = new HTTPMonitor($type['options']);
182
			break;
183 9859b2b5 Darren Embry
		case 'https':
184 939b2d75 Darren Embry
			$mon = new HTTPSMonitor($type['options']);
185
			break;
186 9859b2b5 Darren Embry
		case 'send':
187 939b2d75 Darren Embry
			$mon = new SendMonitor($type['options']);
188
			break;
189
		}
190
		if($mon) {
191
			$check_a[$type['name']] = $mon->p();
192
		}
193
	}
194
	
195 206aa9fc Pierre POMES
  
196 939b2d75 Darren Embry
	$fd = fopen("{$g['varetc_path']}/relayd.conf", "w");
197
	$conf .= "log updates \n";
198
199
	/* Global timeout, interval and prefork settings
200
	   if not specified by the user:
201
	   - use a 1000 ms timeout value as in pfsense 2.0.1 and above
202
	   - leave interval and prefork empty, relayd will use its default values */
203
	
204
	if (isset($setting['timeout']) && !empty($setting['timeout'])) {
205
		$conf .= "timeout ".$setting['timeout']." \n";
206 74b7361f jim-p
	} else {
207 939b2d75 Darren Embry
		$conf .= "timeout 1000 \n";
208
	}
209
	
210
	if (isset($setting['interval']) && !empty($setting['interval'])) {
211
		$conf .= "interval ".$setting['interval']." \n";
212
	}
213
	
214
	if (isset($setting['prefork']) && !empty($setting['prefork'])) {
215
		$conf .= "prefork ".$setting['prefork']." \n";
216
	}
217
	
218
	/* reindex pools by name as we loop through the pools array */
219
	$pools = array();
220
	/* Virtual server pools */
221
	if(is_array($pool_a)) {
222
		for ($i = 0; isset($pool_a[$i]); $i++) {
223
			if(is_array($pool_a[$i]['servers'])) {
224
				if (!empty($pool_a[$i]['retry'])) {
225
					$retrytext = " retry {$pool_a[$i]['retry']}";
226
				} else {
227 0917cb21 Darren Embry
					$retrytext = "";
228 939b2d75 Darren Embry
				}
229 0917cb21 Darren Embry
				$conf .= "table <{$pool_a[$i]['name']}> {\n";
230
				foreach ($pool_a[$i]['servers'] as $server) {
231
					if (is_subnetv4($server)) {
232
						foreach (subnetv4_expand($server) as $ip) {
233
							$conf .= "\t{$ip}{$retrytext}\n";
234
						}
235
					}
236
					else {
237
						$conf .= "\t{$server}{$retrytext}\n";
238
					}
239
				}
240
				$conf .= "}\n";
241 939b2d75 Darren Embry
				/* Index by name for easier fetching when we loop through the virtual servers */
242
				$pools[$pool_a[$i]['name']] = $pool_a[$i];
243
			}
244
		}
245 74b7361f jim-p
	}
246 b6d74873 jim-p
//  if(is_array($protocol_a)) {
247
//    for ($i = 0; isset($protocol_a[$i]); $i++) {
248
//      $proto = "{$protocol_a[$i]['type']} protocol \"{$protocol_a[$i]['name']}\" {\n";
249
//      if(is_array($protocol_a[$i]['lbaction'])) {
250
//        if($protocol_a[$i]['lbaction'][0] == "") {
251
//          continue;
252
//        }
253
//        for ($a = 0; isset($protocol_a[$i]['lbaction'][$a]); $a++) {
254
//          $proto .= "  " . echo_lbaction($protocol_a[$i]['lbaction'][$a]) . "\n";
255
//        }
256
//      }
257
//      $proto .= "}\n";
258
//      $conf .= $proto;
259
//    }
260
//  }
261
262
	$conf .= "dns protocol \"dnsproto\" {\n";
263 0917cb21 Darren Embry
	$conf .= "\t" . "tcp { nodelay, sack, socket buffer 1024, backlog 1000 }\n";
264 b6d74873 jim-p
	$conf .= "}\n";
265
266 327ef8eb Warren Baker
	if(is_array($vs_a)) {
267 0130b756 Warren Baker
		for ($i = 0; isset($vs_a[$i]); $i++) {
268 01ed452e Darren Embry
			
269
			$append_port_to_name = false;
270 6e9b046e jim-p
			if (is_alias($pools[$vs_a[$i]['poolname']]['port'])) {
271
				$dest_port_array = filter_expand_alias_array($pools[$vs_a[$i]['poolname']]['port']);
272 01ed452e Darren Embry
				$append_port_to_name = true;
273
			}
274
			else {
275 6e9b046e jim-p
				$dest_port_array = array($pools[$vs_a[$i]['poolname']]['port']);
276 01ed452e Darren Embry
			}
277 06d84cf3 Darren Embry
			if (is_alias($vs_a[$i]['port'])) {
278
				$src_port_array = filter_expand_alias_array($vs_a[$i]['port']);
279 01ed452e Darren Embry
				$append_port_to_name = true;
280
			}
281 06d84cf3 Darren Embry
			else if ($vs_a[$i]['port']) {
282
				$src_port_array = array($vs_a[$i]['port']);
283
			}
284 01ed452e Darren Embry
			else {
285 06d84cf3 Darren Embry
				$src_port_array = $dest_port_array;
286 01ed452e Darren Embry
			}
287
288
			$append_ip_to_name = false;
289 183ea34c Darren Embry
			if (is_alias($vs_a[$i]['ipaddr'])) {
290 06d84cf3 Darren Embry
				$ip_list = array();
291 183ea34c Darren Embry
				foreach (filter_expand_alias_array($vs_a[$i]['ipaddr']) as $item) {
292 06d84cf3 Darren Embry
					log_error("item is $item");
293 183ea34c Darren Embry
					if (is_subnetv4($item)) {
294
						$ip_list = array_merge($ip_list, subnetv4_expand($item));
295
					}
296
					else {
297
						$ip_list[] = $item;
298
					}
299
				}
300
				$append_ip_to_name = true;
301
			}
302
			else if (is_subnetv4($vs_a[$i]['ipaddr'])) {
303 0917cb21 Darren Embry
				$ip_list = subnetv4_expand($vs_a[$i]['ipaddr']);
304 01ed452e Darren Embry
				$append_ip_to_name = true;
305 0917cb21 Darren Embry
			}
306
			else {
307
				$ip_list = array($vs_a[$i]['ipaddr']);
308
			}
309 01ed452e Darren Embry
310 0917cb21 Darren Embry
			for ($j = 0; $j < count($ip_list); $j += 1) {
311
				$ip = $ip_list[$j];
312 01ed452e Darren Embry
				for ($k = 0; $k < count($src_port_array) && $k < count($dest_port_array); $k += 1) {
313
					$src_port  = $src_port_array[$k];
314
					$dest_port = $dest_port_array[$k];
315
316
					$name = $vs_a[$i]['name'];
317
					if ($append_ip_to_name) {
318
						$name .= "_" . $j;
319 0917cb21 Darren Embry
					}
320 01ed452e Darren Embry
					if ($append_port_to_name) {
321
						$name .= "_" . $src_port;
322 0917cb21 Darren Embry
					}
323
324 01ed452e Darren Embry
					if (($vs_a[$i]['mode'] == 'relay') || ($vs_a[$i]['relay_protocol'] == 'dns')) {
325
						$conf .= "relay \"{$name}\" {\n";
326
						$conf .= "  listen on {$ip} port {$src_port}\n";
327 0917cb21 Darren Embry
328 01ed452e Darren Embry
						if ($vs_a[$i]['relay_protocol'] == "dns") {
329
							$conf .= "  protocol \"dnsproto\"\n";
330
						} else {
331
							$conf .= "  protocol \"{$vs_a[$i]['relay_protocol']}\"\n";
332
						}
333
						$lbmode = "";
334 6e9b046e jim-p
						if ( $pools[$vs_a[$i]['poolname']]['mode'] == "loadbalance" ) {
335 01ed452e Darren Embry
							$lbmode = "mode loadbalance";
336
						}
337 0917cb21 Darren Embry
338 6e9b046e jim-p
						$conf .= "  forward to <{$vs_a[$i]['poolname']}> port {$dest_port} {$lbmode} {$check_a[$pools[$vs_a[$i]['poolname']]['monitor']]} \n";
339 0917cb21 Darren Embry
340 01ed452e Darren Embry
						if (isset($vs_a[$i]['sitedown']) &&  strlen($vs_a[$i]['sitedown']) > 0)
341 6e9b046e jim-p
							$conf .= "  forward to <{$vs_a[$i]['sitedown']}> port {$dest_port} {$lbmode} {$check_a[$pools[$vs_a[$i]['poolname']]['monitor']]} \n";
342 01ed452e Darren Embry
						$conf .= "}\n";
343
					} else  {
344
						$conf .= "redirect \"{$name}\" {\n";
345
						$conf .= "  listen on {$ip} port {$src_port}\n";
346 6e9b046e jim-p
						$conf .= "  forward to <{$vs_a[$i]['poolname']}> port {$dest_port} {$check_a[$pools[$vs_a[$i]['poolname']]['monitor']]} \n";
347 0917cb21 Darren Embry
348 01ed452e Darren Embry
						if (isset($config['system']['lb_use_sticky']))
349
							$conf .= "  sticky-address\n";
350
351
						/* sitedown MUST use the same port as the primary pool - sucks, but it's a relayd thing */
352
						if (isset($vs_a[$i]['sitedown']) && strlen($vs_a[$i]['sitedown']) > 0)
353 6e9b046e jim-p
							$conf .= "  forward to <{$vs_a[$i]['sitedown']}> port {$dest_port} {$check_a[$pools[$vs_a[$i]['poolname']]['monitor']]} \n";
354 01ed452e Darren Embry
355
						$conf .= "}\n";
356
					}
357 b6d74873 jim-p
				}
358 0130b756 Warren Baker
			}
359
		}
360
	}
361
	fwrite($fd, $conf);
362
	fclose($fd);
363
364
	if (is_process_running('relayd')) {
365
		if (! empty($vs_a)) {
366 d3534235 jim-p
			if ($kill_first) {
367
				mwexec('pkill relayd');
368
				mwexec("/usr/local/sbin/relayd -f {$g['varetc_path']}/relayd.conf");
369
			} else {
370
				// it's running and there is a config, just reload
371
				mwexec("/usr/local/sbin/relayctl reload");
372
			}
373 0130b756 Warren Baker
		} else {
374
			/*
375
			 * XXX: Something breaks our control connection with relayd
376
			 * and makes 'relayctl stop' not work
377
			 * rule reloads are the current suspect
378
			 * mwexec('/usr/local/sbin/relayctl stop');
379
			 *  returns "command failed"
380
			 */
381
			mwexec('pkill relayd');
382
		}
383 b1bd2119 Chris Buechler
	} else {
384 0130b756 Warren Baker
		if (! empty($vs_a)) {
385
			// not running and there is a config, start it
386
			mwexec("/usr/local/sbin/relayd -f {$g['varetc_path']}/relayd.conf");
387
		}
388 b1bd2119 Chris Buechler
	}
389 3ad6d3bb Bill Marquette
}
390
391 a776c720 jim-p
function get_lb_redirects() {
392
/*
393
# relayctl show summary
394
Id   Type      Name                      Avlblty Status
395
1    redirect  testvs2                           active
396
5    table     test2:80                          active (3 hosts up)
397
11   host      192.168.1.2               91.55%  up
398
10   host      192.168.1.3               100.00% up
399
9    host      192.168.1.4               88.73%  up
400
3    table     test:80                           active (1 hosts up)
401
7    host      192.168.1.2               66.20%  down
402
6    host      192.168.1.3               97.18%  up
403
0    redirect  testvs                            active
404
3    table     test:80                           active (1 hosts up)
405
7    host      192.168.1.2               66.20%  down
406
6    host      192.168.1.3               97.18%  up
407
4    table     testvs-sitedown:80                active (1 hosts up)
408
8    host      192.168.1.4               84.51%  up
409
# relayctl show redirects
410
Id   Type      Name                      Avlblty Status
411
1    redirect  testvs2                           active
412
0    redirect  testvs                            active
413
# relayctl show redirects
414
Id   Type      Name                      Avlblty Status
415
1    redirect  testvs2                           active
416
           total: 2 sessions
417
           last: 2/60s 2/h 2/d sessions
418
           average: 1/60s 0/h 0/d sessions
419
0    redirect  testvs                            active
420
*/
421
	$rdr_a = array();
422
	exec('/usr/local/sbin/relayctl show redirects 2>&1', $rdr_a);
423 b6d74873 jim-p
	$relay_a = array();
424
	exec('/usr/local/sbin/relayctl show relays 2>&1', $relay_a);
425 a776c720 jim-p
	$vs = array();
426 ff160984 jim-p
	$cur_entry = "";
427 a776c720 jim-p
	for ($i = 0; isset($rdr_a[$i]); $i++) {
428
		$line = $rdr_a[$i];
429
		if (preg_match("/^[0-9]+/", $line)) {
430
			$regs = array();
431
			if($x = preg_match("/^[0-9]+\s+redirect\s+([^\s]+)\s+([^\s]+)/", $line, $regs)) {
432 ff160984 jim-p
				$cur_entry = trim($regs[1]);
433 a776c720 jim-p
				$vs[trim($regs[1])] = array();
434
				$vs[trim($regs[1])]['status'] = trim($regs[2]);
435
			}
436 ff160984 jim-p
		} elseif (($x = preg_match("/^\s+total:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
437
			$vs[$cur_entry]['total'] = trim($regs[1]);
438
		} elseif (($x = preg_match("/^\s+last:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
439
			$vs[$cur_entry]['last'] = trim($regs[1]);
440
		} elseif (($x = preg_match("/^\s+average:(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
441
			$vs[$cur_entry]['average'] = trim($regs[1]);
442 a776c720 jim-p
		}
443
	}
444 ff160984 jim-p
	$cur_entry = "";
445 b6d74873 jim-p
	for ($i = 0; isset($relay_a[$i]); $i++) {
446
		$line = $relay_a[$i];
447
		if (preg_match("/^[0-9]+/", $line)) {
448
			$regs = array();
449
			if($x = preg_match("/^[0-9]+\s+relay\s+([^\s]+)\s+([^\s]+)/", $line, $regs)) {
450 ff160984 jim-p
				$cur_entry = trim($regs[1]);
451 b6d74873 jim-p
				$vs[trim($regs[1])] = array();
452
				$vs[trim($regs[1])]['status'] = trim($regs[2]);
453
			}
454 ff160984 jim-p
		} elseif (($x = preg_match("/^\s+total:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
455
			$vs[$cur_entry]['total'] = trim($regs[1]);
456
		} elseif (($x = preg_match("/^\s+last:\s(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
457
			$vs[$cur_entry]['last'] = trim($regs[1]);
458
		} elseif (($x = preg_match("/^\s+average:(.*)\ssessions/", $line, $regs)) && !empty($cur_entry)) {
459
			$vs[$cur_entry]['average'] = trim($regs[1]);
460 b6d74873 jim-p
		}
461
	}
462 a776c720 jim-p
	return $vs;
463
}
464
465
function get_lb_summary() {
466
	$relayctl = array();
467
	exec('/usr/local/sbin/relayctl show summary 2>&1', $relayctl);
468
	$relay_hosts=Array();
469
	foreach( (array) $relayctl as $line) {
470 cfbfd941 smos
		$t = explode("\t", $line);
471 a776c720 jim-p
		switch (trim($t[1])) {
472
			case "table":
473
				$curpool=trim($t[2]);
474 9859b2b5 Darren Embry
				break;
475 a776c720 jim-p
			case "host":
476
				$curhost=trim($t[2]);
477
				$relay_hosts[$curpool][$curhost]['avail']=trim($t[3]);
478
				$relay_hosts[$curpool][$curhost]['state']=trim($t[4]);
479 9859b2b5 Darren Embry
				break;
480 a776c720 jim-p
		}
481
	}
482
	return $relay_hosts;
483
}
484
485 9b0ddd8c Ermal
?>