diff options
-rw-r--r-- | config/haproxy-devel/haproxy.inc | 123 | ||||
-rw-r--r-- | config/haproxy-devel/haproxy.xml | 15 | ||||
-rwxr-xr-x | config/haproxy-devel/haproxy_global.php | 8 | ||||
-rw-r--r-- | config/haproxy-devel/haproxy_listeners.php | 8 | ||||
-rw-r--r-- | config/haproxy-devel/haproxy_pool_edit.php | 35 | ||||
-rw-r--r-- | config/haproxy-devel/haproxy_pools.php | 8 |
6 files changed, 161 insertions, 36 deletions
diff --git a/config/haproxy-devel/haproxy.inc b/config/haproxy-devel/haproxy.inc index 89103ef8..0f6de3de 100644 --- a/config/haproxy-devel/haproxy.inc +++ b/config/haproxy-devel/haproxy.inc @@ -422,6 +422,9 @@ function write_backend($fd, $name, $pool, $frontend) { $pool['retries'] = 3; fwrite ($fd, "\tretries\t\t\t" . $pool['retries'] . "\n"); + if ($pool['transparent_clientip']) + fwrite ($fd, "\tsource 0.0.0.0 usesrc clientip\n"); + if($pool['stats_enabled']=='yes') { fwrite ($fd, "\tstats\t\t\tenable\n"); if($pool['stats_uri']) @@ -505,13 +508,17 @@ function write_backend($fd, $name, $pool, $frontend) { } function haproxy_configure() { + global $g; // reload haproxy - haproxy_writeconf(); + haproxy_writeconf("{$g['varetc_path']}/haproxy.cfg"); return haproxy_check_run(1); } -function haproxy_check_writtenconfig_error(&$messages) { - $retval = exec("haproxy -c -V -f /var/etc/haproxy.cfg 2>&1", $output, $err); +function haproxy_check_and_run(&$messages, $reload) { + global $g; + $configname = "{$g['varetc_path']}/haproxy.cfg"; + haproxy_writeconf("$configname.new"); + $retval = exec("haproxy -c -V -f $configname.new 2>&1", $output, $err); $messages = ""; if ($err > 1) $messages = "<h2><strong>FATAL ERROR CODE: $err while starting haproxy</strong></h2>"; @@ -523,17 +530,24 @@ function haproxy_check_writtenconfig_error(&$messages) { foreach($output as $line) $messages .= "<br/>" . htmlspecialchars($line) . "\n"; } - return (strstr($retval, "Configuration file is valid")); + $ok = strstr($retval, "Configuration file is valid"); + if ($ok && $reload) { + global $haproxy_run_message; + exec("mv $configname.new $configname"); + $ok = haproxy_check_run(1) == 0; + $messages = $haproxy_run_message; + } + return $ok; } -function haproxy_writeconf() { - global $config, $g; +function haproxy_writeconf($configfile) { + global $config; $a_global = &$config['installedpackages']['haproxy']; $a_backends = &$config['installedpackages']['haproxy']['ha_backends']['item']; $a_pools = &$config['installedpackages']['haproxy']['ha_pools']['item']; - $fd = fopen("{$g['varetc_path']}/haproxy.cfg", "w"); + $fd = fopen($configfile, "w"); if(is_array($a_global)) { fwrite ($fd, "global\n"); @@ -541,7 +555,10 @@ function haproxy_writeconf() { if($a_global['remotesyslog']) fwrite ($fd, "\tlog\t\t\t{$a_global['remotesyslog']}\t{$a_global['logfacility']}\t{$a_global['loglevel']}\n"); fwrite ($fd, "\tstats socket /tmp/haproxy.socket level admin\n"); - fwrite ($fd, "\tuid\t\t\t80\n"); + + if(!use_transparent_clientip_proxying()) + fwrite ($fd, "\tuid\t\t\t80\n"); + fwrite ($fd, "\tgid\t\t\t80\n"); // Set numprocs if defined or use system default (#cores) if($a_global['nbproc']) @@ -831,13 +848,91 @@ function haproxy_is_running() { return $running; } + +function haproxy_load_modules() { + // On FreeBSD 8 ipfw is needed to allow 'transparent' proxying (getting reply's to a non-local ip to pass back to the client-socket).. + // On FreeBSD 9 it is probably possible to do the same with the pf option "divert-reply" + mute_kernel_msgs(); + if (!is_module_loaded("ipfw.ko")) { + mwexec("/sbin/kldload ipfw"); + /* make sure ipfw is not on pfil hooks */ + mwexec("/sbin/sysctl net.inet.ip.pfil.inbound=\"pf\" net.inet6.ip6.pfil.inbound=\"pf\"" . + " net.inet.ip.pfil.outbound=\"pf\" net.inet6.ip6.pfil.outbound=\"pf\""); + } + /* Activate layer2 filtering */ + mwexec("/sbin/sysctl net.link.ether.ipfw=1"); + unmute_kernel_msgs(); +} + +function use_transparent_clientip_proxying() { + global $config; + $a_backends = &$config['installedpackages']['haproxy']['ha_pools']['item']; + foreach ($a_backends as $backend) { + if ($backend["transparent_clientip"] == 'yes') { + return true; + break; + } + } + return false; +} + +function load_ipfw_rules() { + // On FreeBSD 8 pf does not support "divert-reply" so ipfw is needed. + global $g, $config; + $ipfw_zone_haproxy = "haproxy"; + + $a_backends = &$config['installedpackages']['haproxy']['ha_pools']['item']; + + haproxy_load_modules(); + + $transparent_backends = array(); + foreach ($a_backends as $backend) { + if ($backend["transparent_clientip"] != 'yes') + continue; + $real_if = get_real_interface($backend["transparent_interface"]); + $a_servers = &$backend['ha_servers']['item']; + foreach($a_servers as $server) { + if (is_array($a_servers)) { + + foreach($a_servers as $be) { + if (!$be['status'] == "inactive") + continue; + if (!is_ipaddr($be['address'])) + continue; + $item = array(); + $item['address'] = $be['address']; + $item['port'] = $be['port']; + $item['interface'] = $real_if;//"em0"; + $transparent_backends[] = $item; + } + } + } + } + mwexec("/usr/local/sbin/ipfw_context -a $ipfw_zone_haproxy", true); + mwexec("/usr/local/sbin/ipfw_context -a $ipfw_zone_haproxy -n em0", true); + $rulenum = 64000; // why that high? captiveportal.inc also does it... + $rules = "flush\n"; + foreach($transparent_backends as $transparent_be) { + $rules .= "add $rulenum fwd localhost tcp from {$transparent_be["address"]} {$transparent_be["port"]} to any in recv {$transparent_be["interface"]}\n"; + $rulenum++; + } + + + file_put_contents("{$g['tmp_path']}/ipfw_{$ipfw_zone_haproxy}.haproxy.rules", $rules); + mwexec("/usr/local/sbin/ipfw_context -s $ipfw_zone_haproxy", true); + mwexec("/sbin/ipfw -x $ipfw_zone_haproxy -q {$g['tmp_path']}/ipfw_{$ipfw_zone_haproxy}.haproxy.rules", true); +} + function haproxy_check_run($reload) { - global $config, $g; + global $config, $g, $haproxy_run_message; $a_global = &$config['installedpackages']['haproxy']; exec("/usr/bin/limits -n 300014"); + if(use_transparent_clientip_proxying()) + load_ipfw_rules(); + if(isset($a_global['enable'])) { if (isset($a_global['carpdev'])) { $status = get_carp_interface_status($a_global['carpdev']); @@ -856,16 +951,18 @@ function haproxy_check_run($reload) { return (0); if (haproxy_is_running()) { - exec("/usr/local/sbin/haproxy -f /var/etc/haproxy.cfg -p /var/run/haproxy.pid -st `cat /var/run/haproxy.pid`"); + exec("/usr/local/sbin/haproxy -f /var/etc/haproxy.cfg -p /var/run/haproxy.pid -st `cat /var/run/haproxy.pid` 2>&1", $output, $errcode); } else { - exec("/usr/local/sbin/haproxy -f /var/etc/haproxy.cfg -p /var/run/haproxy.pid -D"); + exec("/usr/local/sbin/haproxy -f /var/etc/haproxy.cfg -p /var/run/haproxy.pid -D 2>&1", $output, $errcode); } - return (0); + foreach($output as $line) + $haproxy_run_message .= "<br/>" . htmlspecialchars($line) . "\n"; + return ($errcode); } else { if ($reload && haproxy_is_running()) { exec("/bin/pkill -F /var/run/haproxy.pid haproxy"); } - return (1); + return (0); } } diff --git a/config/haproxy-devel/haproxy.xml b/config/haproxy-devel/haproxy.xml index 39ec183e..0d03527c 100644 --- a/config/haproxy-devel/haproxy.xml +++ b/config/haproxy-devel/haproxy.xml @@ -89,6 +89,21 @@ <chmod>077</chmod> <item>http://www.pfsense.com/packages/config/haproxy-devel/haproxy_pool_edit.php</item> </additional_files_needed> + <additional_files_needed> + <prefix>/usr/local/pkg/</prefix> + <chmod>077</chmod> + <item>http://www.pfsense.com/packages/config/haproxy-devel/haproxy_socketinfo.inc</item> + </additional_files_needed> + <additional_files_needed> + <prefix>/usr/local/www/widgets/include/</prefix> + <chmod>077</chmod> + <item>http://www.pfsense.com/packages/config/haproxy-devel/haproxy.widget.inc</item> + </additional_files_needed> + <additional_files_needed> + <prefix>/usr/local/www/widgets/widgets/</prefix> + <chmod>077</chmod> + <item>http://www.pfsense.com/packages/config/haproxy-devel/haproxy.widget.php</item> + </additional_files_needed> <custom_delete_php_command> </custom_delete_php_command> <custom_add_php_command> diff --git a/config/haproxy-devel/haproxy_global.php b/config/haproxy-devel/haproxy_global.php index 2ff65c0e..7ff0fb65 100755 --- a/config/haproxy-devel/haproxy_global.php +++ b/config/haproxy-devel/haproxy_global.php @@ -42,13 +42,7 @@ if ($_POST) { $pconfig = $_POST; if ($_POST['apply']) { - $retval = 0; - config_lock(); - $retval = haproxy_configure(); - config_unlock(); - - $result = haproxy_check_writtenconfig_error($messages); - $savemsg = $messages; + $result = haproxy_check_and_run($savemsg, true); if ($result) unlink_if_exists($d_haproxyconfdirty_path); } else { diff --git a/config/haproxy-devel/haproxy_listeners.php b/config/haproxy-devel/haproxy_listeners.php index 03262c48..d634ded4 100644 --- a/config/haproxy-devel/haproxy_listeners.php +++ b/config/haproxy-devel/haproxy_listeners.php @@ -42,13 +42,7 @@ if ($_POST) { $pconfig = $_POST; if ($_POST['apply']) { - $retval = 0; - config_lock(); - $retval = haproxy_configure(); - config_unlock(); - - $result = haproxy_check_writtenconfig_error($messages); - $savemsg = $messages; + $result = haproxy_check_and_run($savemsg, true); if ($result) unlink_if_exists($d_haproxyconfdirty_path); } diff --git a/config/haproxy-devel/haproxy_pool_edit.php b/config/haproxy-devel/haproxy_pool_edit.php index a1a3c69e..e282504a 100644 --- a/config/haproxy-devel/haproxy_pool_edit.php +++ b/config/haproxy-devel/haproxy_pool_edit.php @@ -50,7 +50,7 @@ if (isset($_GET['dup'])) global $simplefields; $simplefields = array( -"name","cookie","balance", +"name","cookie","balance","transparent_clientip","transparent_interface", "check_type","checkinter","httpcheck_method","monitor_uri","monitor_httpversion","monitor_username","monitor_domain","monitor_agentport", "connection_timeout","server_timeout","retries", "stats_enabled","stats_username","stats_password","stats_uri","stats_realm","stats_admin","stats_node_enabled","stats_node","stats_desc","stats_refresh"); @@ -235,6 +235,8 @@ foreach($simplefields as $field){ .haproxy_check_http{display:none;} .haproxy_check_username{display:none;} .haproxy_check_smtp{display:none;} + .haproxy_transparent_clientip{display:none;} + .haproxy_check_agent{display:none;} </style> <script language="javascript"> function clearcombo(){ @@ -271,6 +273,9 @@ foreach($simplefields as $field){ setCSSdisplay(".haproxy_check_smtp", check_type == 'SMTP' || check_type == 'ESMTP'); setCSSdisplay(".haproxy_check_agent", check_type == 'Agent'); + transparent_clientip = d.getElementById("transparent_clientip"); + setCSSdisplay(".haproxy_transparent_clientip", transparent_clientip.checked); + monitor_username = d.getElementById("monitor_username"); sqlcheckusername = d.getElementById("sqlcheckusername"); if(!browser_InnerText_support){ @@ -486,6 +491,32 @@ foreach($simplefields as $field){ </table> </td> </tr> + <tr align="left" style="display:none;"> + <td width="22%" valign="top" class="vncell">Transparent ClientIP</td> + <td width="78%" class="vtable" colspan="2"> + <input id="transparent_clientip" name="transparent_clientip" type="checkbox" value="yes" <?php if ($pconfig['transparent_clientip']=='yes') echo "checked"; ?> onclick='updatevisibility();'> + Use Client-IP to connect to backend servers. + <div class="haproxy_transparent_clientip"> + + <? + $interfaces = get_configured_interface_with_descr(); + $interfaces2 = array(); + foreach($interfaces as $key => $name) + { + + $interfaces2[$key]['name'] = $name; + } + echo_html_select("transparent_interface",$interfaces2,$pconfig['transparent_interface']?$pconfig['transparent_interface']:"lan","","updatevisibility();"); + ?>Interface that will connect to the backend server. (this will generally be your LAN or OPT1(dmz) interface)<br/> + </div> + <br/> + Connect transparently to the backend server's so the connection seams to come straight from the client ip address. + For proper workings this requires the reply's traffic to pass through pfSense by means of correct routing. + (uses the option "source 0.0.0.0 usesrc clientip") + <br/><br/> + Note : When this is enabled for a single backend HAProxy will run as 'root', which reduces security. + </td> + </tr> <tr align="left"> <td width="22%" valign="top" class="vncell">Per server pass thru</td> <td width="78%" class="vtable" colspan="2"> @@ -514,7 +545,7 @@ foreach($simplefields as $field){ <td width="22%" valign="top" class="vncell">Health check method</td> <td width="78%" class="vtable" colspan="2"> <? - echo_html_select("check_type",$a_checktypes,$pconfig['check_type']?$pconfig['check_type']:"HTML","","updatevisibility();"); + echo_html_select("check_type",$a_checktypes,$pconfig['check_type']?$pconfig['check_type']:"HTTP","","updatevisibility();"); ?><br/> <textarea readonly="yes" cols="60" rows="2" id="check_type_description" name="check_type_description" style="padding:5px; border:1px dashed #990000; background-color: #ffffff; color: #000000; font-size: 8pt;"></textarea> </td> diff --git a/config/haproxy-devel/haproxy_pools.php b/config/haproxy-devel/haproxy_pools.php index cd3899e6..2d0189a5 100644 --- a/config/haproxy-devel/haproxy_pools.php +++ b/config/haproxy-devel/haproxy_pools.php @@ -47,13 +47,7 @@ if ($_POST) { $pconfig = $_POST; if ($_POST['apply']) { - $retval = 0; - config_lock(); - $retval = haproxy_configure(); - config_unlock(); - - $result = haproxy_check_writtenconfig_error($messages); - $savemsg = $messages; + $result = haproxy_check_and_run($savemsg, true); if ($result) unlink_if_exists($d_haproxyconfdirty_path); } |