Block hosts with firewall rules w/internal redirect to Deny Page.



  • Worked with firewalls for many years. New to pfSense but a serious believer.

    Moving Watchguard x550e Fireboxes to pfSense.

    Watchguard firewall has HTTP-proxy rule that allows me to deny a request by returning a page defined as part of the rule. When I enable this rule, users attempting to access my host websites see a "Server is down for maintenance" page. I don't know how this is done internally but the result is the user sees the "Server Down" page without any change to the browser URL (no external redirect).

    I am unclear on how best to do this on pfSense. My preference is to use the firewall since it would allow me the ability to maintain several rules any one of which I might enable to deny access to all or some of my hosts.

    Captive Portal seems like it might have possibilities but it appears there is not room for more than a single configuration.

    Squid or SquidGuard could be used, I suppose, but that seems like a heavy load for such a simple need.

    Any suggestions or examples would be appreciated.



  • Create a forward NAT on your LAN adapter with a source address of private IP's (or alias IP pool) you want redirected, the dest/nat ports to the web server port and NAT IP to web server IP.  This of course creates a matching LAN rule.  You may have to enable by checkbox in System, Advance, Firewall the "bypass firewall rules for traffic on the same interface" if it doesn't behave as expected.  If you redirect port 80 from Lan>Lan you may want to modify your WebConfig port from port 80 to something non-standard.



  • Thanks for the reply, Mark. Sorry I didn't respond sooner. I was not aware I had to turn on Notify to get emailed when you responded.

    Yes, NAT would seem to be the only easy answer I can find. I assume you're suggesting forwarding HTTP requests to a simple HTTPD that returns only a "Server is Down" page regardless of the requested URL or payload. Yes, I probably can do that. It would be great if I could install something small on the pfSense device, itself that could handle this.

    Can you think of anything lightweight that can do this?



  • I agree it seems that Squid is too heavy, and captive portal is too restrictive for a simple HTTP redirect.  Below is the NAT and LAN rule.  It requires an external HTTP server.  I have this setup working fine but would like the web server to be internal to PfSense.  I've been looking at the vHosts package to see if it is needed or if the built in lighttpd web server can do this task natively.  My thought is if nothing else vHosts might provide a UI to lighttpd rather than doing from command line.

    NAT PORT FORWARD;

    • LAN1, TCP, <redirected source="" ip="">, any, HTTP, <http server="" ip="">, HTTP

    LAN RULE;

    • IPv4, <redirected source="" ip="">, any, <http server="" ip="">, HTTP, any, none, *</http></redirected></http></redirected>


  • From what I'm reading, vHosts looks like a bust. There is no documentation and it apparently does not indicate it is running even when it is. It looks like no one intends to continue supporting it so I'm going to most likely stay away.

    Your idea of using another instance of lighttpd seems promising. Apparently, Captive Portal does just that. In the 2.1 release, multiple instances of Captive Portal are possible. I may look into that.



  • There is a fix for vHosts not showing as an active service when it is.  But if not supported then ya why go there.  If you manage to get two instances of lighttpd running please come back and share.

    This may be helpful.
    http://forum.pfsense.org/index.php?topic=47316.0



  • @sthames42:

    From what I'm reading, vHosts looks like a bust. There is no documentation and it apparently does not indicate it is running even when it is. It looks like no one intends to continue supporting it so I'm going to most likely stay away.

    Your idea of using another instance of lighttpd seems promising. Apparently, Captive Portal does just that. In the 2.1 release, multiple instances of Captive Portal are possible. I may look into that.

    Been using vHosts for quite a while with no problem. You can search the forums to find the fix for it not showing status - although I'm trying to remember - it may have been fixed in 2.1.



  • @rjcrowder:

    Been using vHosts for quite a while with no problem. You can search the forums to find the fix for it not showing status - although I'm trying to remember - it may have been fixed in 2.1.

    RJ, does vHosts look like it will fit the requirement? How big a footprint does it have? The only time I would need this other server is when I want to block access to some or all of my websites. I don't want a heavy process running all the time if it's rarely used.

    Everything I find on vHosts says no one cares about continuing support. Do you have any idea if vHosts will continue to be available in future releases of pfSense?



  • I'd prefer to use a package to better ensure full integration with PfSense.  If not available, here's a hack that suggests creating a second Lighttpd port pointing to alternate content.  I haven't tried it out yet but may soon on my test box.

    http://comments.gmane.org/gmane.comp.web.lighttpd/3270



  • @sthames42:

    RJ, does vHosts look like it will fit the requirement? How big a footprint does it have? The only time I would need this other server is when I want to block access to some or all of my websites. I don't want a heavy process running all the time if it's rarely used.

    Everything I find on vHosts says no one cares about continuing support. Do you have any idea if vHosts will continue to be available in future releases of pfSense?

    I'm not sure about doing what you want with vHosts…

    It's one process that runs. I don't know how much memory it takes, but it can't be much. All I use it for is to host a dansguardian bypass page. Also not sure about long term support, but there isn't much to it. The only other issue I had with it is that it doesn't always properly create the /var/run pid file... It was easy enough fix by changing the start line in /usr/local/pkg/vhosts.inc. See attached patch.

    786c786
    < 		"start" => "/usr/local/sbin/lighttpd -f /var/etc/vhosts-http.conf",
    ---
    > 		"start" => "/usr/local/sbin/lighttpd -f /var/etc/vhosts-http.conf; ps -ax | grep vhosts-http.conf | grep '/usr/local/sbin' | sed -e 's/^[[:space:]]*//' | cut -f1 -d ' ' > /var/run/vhosts-http.pid",
    
    


  • @rjcrowder:

    It was easy enough fix by changing the start line in /usr/local/pkg/vhosts.inc. See attached patch.

    786c786
    < 		"start" => "/usr/local/sbin/lighttpd -f /var/etc/vhosts-http.conf",
    ---
    > 		"start" => "/usr/local/sbin/lighttpd -f /var/etc/vhosts-http.conf; ps -ax | grep vhosts-http.conf | grep '/usr/local/sbin' | sed -e 's/^[[:space:]]*//' | cut -f1 -d ' ' > /var/run/vhosts-http.pid",
    
    

    RJ, I finally got back to this and found this patch worked quite well. I patched the vhosts.inc file and then told pfSense to reinstall the package. This created the /usr/local/etc/rc.d/vhosts-http.sh file correctly and the pid file was created correctly after the next reboot. Great!

    Funny thing, though. After the reinstall, the vhosts-http.sh file was fine and included the modified start command from vhosts.inc. But vhosts.inc NO LONGER HAD the modified start command. Somehow, the reinstall used the modified vhosts.inc file to reinstall the package and then re-downloaded the vhosts.inc file from the pfSense site.

    When does the /usr/local/etc/rc.d/vhosts-http.sh file get recreated? Is it only on an install or re-install? Does it make more sense to modify the vhosts-http.sh file directly after the package is installed?



  • Ok, I got this working but it took some changes to the vhosts package. In case anyone else has this issue, here is how it was solved.

    As I noted above, the Watchguard Firebox software we originally used made it possible to create a firewall rule such that page content was created in the rule for response to the request. If I wanted to say the server was down for maintenance, I could enable a predefined rule on the firewall that would return a "Server Unavailable" page without the need for a web server on the inside of the firewall. This meant I could bring down any site or server by just enabling a rule. Now, because this is done in the firewall, I can only redirect an IP–not a specific virtual host. But that is sufficient for my needs.

    This feature I can now emulate in pfSense using the vhosts package. Here are the issues I needed to fix:

    • vhost-http service did not show as started following a reboot.
      This was happening because lighttpd was not correctly creating the PID file after the device rebooted. This was only after a reboot but the only way to correct it was to connect to the box through a terminal, kill the service, and then start it in the UI.
      Thanks to RJ for the fix above which worked flawlessly. But the rc file was only created when the package was installed.
      I modified it to create the rc file whenever the device rebooted.

    • Request IP/Port AND Host Name had to match the vhost settings for the host to be found.
      I could not specify just an IP/Port based virtual host. The host name had to match the request. If I wanted to forward requests from multiple sites to a single vhost, I could only do it by creating a vhost entry for each IP/Port/Host combination.
      I modified the configuration file creator to check for an asterisk (*) in the host name. If found, no host name match is included in the vhost configuration. A match for the IP/Port is all that is required.

    • Could not return "Server Unavailable" page for all requests.
      There was no way to further modify the configuration file in the UI and lighttpd does not provide for ".htaccess" files as Apache does.
      I modified the configuration file creator to look for the file "vhost.conf" in the vhost server root folder. If found, the configuration settings are added to the configuration for the vhost.

    These changes have not been tested against any but my very narrow set of needs so they will certainly break under some requirement out there. But here is the patch of changes to /usr/local/pkg/vhosts.inc. This patch was made to the vhosts package version 0.7.4 and 0.7.5 on pfSense 2.1.5.

    --- vhosts-0.7.4.inc	2014-10-21 13:06:27.000000000 -0700
    +++ vhosts.inc	2014-10-21 12:44:26.000000000 -0700
    @@ -29,6 +29,22 @@
     	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     	POSSIBILITY OF SUCH DAMAGE.
    +	
    +	SM001 9/10/2014
    +	The PID of the server is not captured by lighttpd on a reboot and the PID file
    +	is created as an empty file. The PID file is created correctly when the
    +	service is started from the UI. This appears to be an issue with lighttpd. 
    +	vhosts_sync_package_php() has been modified to create the rc file to capture 
    +	the PID after the service is started and create the PID file. Also, the main 
    +	rc file is created in the sync method instead of the install method so changes
    +	to the creation of the rc file in this file will be seen in the rc file on the
    +	next reboot.
    +	
    +	SM002 9/11/2014
    +	Added IP/Port vhosts and per-host configuration files. If the host name begins
    +	with an asterisk (*), no host match restriction is include for the host. All
    +	hostnames on the socket will work. Configuration settings found in "vhost.conf"
    +	in the host directory are included if the file exists.
     */
    
     //show errors
    @@ -149,6 +165,22 @@
     		//HTTP configuration
     		if (count($vhostarray_http) > 0) {
    
    +			#*---------------------------------*
    +			#* SM001 - Write the HTTP rc file. *
    +			#*---------------------------------*
    +			if (!function_exists('write_rcfile')) { require("/etc/inc/service-utils.inc"); }
    +			$cf = "/var/etc/vhosts-http.conf";
    +			$pf = "/var/run/vhosts-http.pid";
    +			write_rcfile(array
    +				(
    +				"file"  => "vhosts-http.sh", 
    +				"start" => "/usr/local/sbin/lighttpd -f '$cf'; ps ax | grep '$cf' | grep -v grep | sed 's/^ *//' | cut -f1 -d ' ' > '$pf'",
    +				"stop"  => "kill `cat '$pf'`"
    +				));
    +			#*-------*
    +			#* SM001 *
    +			#*-------*
    +
     			$tmp = "#\n";
     			$tmp .= "# lighttpd configuration file\n";
     			$tmp .= "#\n";
    @@ -297,9 +329,14 @@
     						$privatekey = base64_decode($rowhelper['privatekey']);
     					}
    
    +					#*--------------------------------------*
    +					#* SM002 - If not set, get directory    *
    +					#* from host but skip leading star (*). *
    +					#*--------------------------------------*
     					//set directory default to the host
    -						if (strlen($directory) == 0) { $directory = $host; }
    -
    +						//if (strlen($directory) == 0) { $directory = $host; }
    +						if (strlen($directory) == 0) { $directory = ($host[0] == "*" ? substr($host, 1) : $host); }
    +						
     					//if the vhost directory doesn't exist then create it
     						//echo '/usr/local/vhosts/'.$directory.'
    ';
     						if (!is_dir('/usr/local/vhosts/'.$directory)) {
    @@ -324,7 +361,13 @@
     						$tmp .= "\$SERVER[\"socket\"] == \"".$ipaddress.":".$port."\" {\n";
     					}
    
    -					$tmp .= "	\$HTTP[\"host\"] == \"".$host."\" {\n";
    +					#*-------------------------------------------*
    +					#* SM002 - If host name starts with asterisk *
    +					#* (*), allow all hosts for this socket.     *
    +					#*-------------------------------------------*
    +					if ($host[0] != "*")
    +						$tmp .= "	\$HTTP[\"host\"] == \"".$host."\" {\n";
    +						
     					$tmp .= "		server.document-root        = \"/usr/local/vhosts/".$directory."\"\n";
    
     					//enable ssl if the cert and key were both provided
    @@ -337,7 +380,15 @@
     						$tmp .= "		ssl.engine = \"enable\"\n";
     						unset($pem_file);
     					}
    -					if (count($vhostarray_http) > 0) {
    +					
    +					#*-----------------------------------------*
    +					#* SM002 - Include vhost config file if    *
    +					#* any and close the host scope if opened. *
    +					#*-----------------------------------------*
    +					$tmp .= "include_shell \"[ -f '/usr/local/vhosts/$directory/vhost.conf' ] && cat '/usr/local/vhosts/$directory/vhost.conf'\"\n";
    +					
    +					if ($host[0] != "*") {
    +					//if (count($vhostarray_http) > 0) {
     						$tmp .= "	}\n";
     					}
    
    

    After installing the package, patch the file and reboot the router. Remember these changes will be wiped out by a package reinstall.

    Note: If you are modifying a nanobsd image on a CF card as I am, go to Diagnostics->NanoBSD->Media Read/Write Status and make the CF card writable before you patch the file.


Log in to reply