{"id":595,"date":"2012-12-14T14:37:04","date_gmt":"2012-12-14T19:37:04","guid":{"rendered":"http:\/\/chewie.potsdam.edu\/?page_id=595"},"modified":"2013-04-20T00:19:10","modified_gmt":"2013-04-20T00:19:10","slug":"intercepting-inline-proxy-based-nac","status":"publish","type":"page","link":"https:\/\/www.gregkuchyt.net\/?page_id=595","title":{"rendered":"Intercepting Inline Proxy based NAC"},"content":{"rendered":"<p>Using Linux, IPTables, Apache, Perl, MySQL, and Squid to create an in-line NAC content caching router.<\/p>\n<h2>Background<\/h2>\n<p>We currently utilize a network registration built upon the RFCs for how clients should deal with DNS servers. The idea being that we give out a bogus DNS server as the first one in the list in the DHCP lease. This bogus DNS server resolves all DNS requests to itself. This effectively captures any browser traffic which gets redirected to a web application that handles network registration over HTTPS on a network registration appliance. This appliance is just a Linux box running a LAMP stack and doing routing. Historically this solution worked great, until clients started not following the RFCs. Initially beginning with Macs (not surprising) we have seen an increasing number of clients that break against our network registration system. Essentially these clients do not proceed through the hierarchy of received DNS servers as they should if following the RFC. As such, it is clear that our current solution is untenable and we need a solution that will work more universally.<\/p>\n<h2>Proposed Solution<\/h2>\n<p>Looking at similar solutions implemented in production, we deduced that reverse proxying was a popular method to funnel clients to a registration application. The basic idea is to redirect all tcp port 80 traffic to the registration application, then via IPTables exclude them from that redirection and pass traffic normally. A variation on this idea is after registration, setup IPTables to pass traffic transparently through an inline caching proxy to potentially decrease the hit on our inbound bandwidth. This variation places a bit more complicated setup in place, but with a diagram of IPTables it is easy to understand how all the piece come together.<\/p>\n<h2>Implementation<\/h2>\n<p>This implementation guide is written assuming a Red Hat Enterprise Linux 6.3 or EL clone distribution, while all the concepts will work for any Linux distribution some of the details may not be accurate.<\/p>\n<h3>Routing<\/h3>\n<p>This is a pretty simple thing to enable in Linux. Simply edit \/etc\/sysctl.conf and add the following:<\/p>\n<p><code class=\"block\">net.ipv4.ip_forward = 1<\/code><\/p>\n<p>then run<\/p>\n<p><code class=\"block\">#sysctl -p<\/code><\/p>\n<p>As well, you&#8217;ll want to make sure that your routing tables has the appropriate routes set and that a default gateway route is established to get to your next hop.<\/p>\n<h3>Squid<\/h3>\n<p>Squid is pretty simple to configure for this. By default Squid ships with a minimal config file that doesn&#8217;t really allow Squid to be that useful but it makes Squid pretty locked down. You&#8217;ll want to make the following changes to the stock config.<\/p>\n<p>(1) Allow the routed network access to squid<\/p>\n<p><code class=\"block\">acl devnet src 10.10.48.0\/20<\/code><\/p>\n<p>(2) Uncomment the line that reads<\/p>\n<p><code class=\"block\">#http_access deny to_localhost<\/code><\/p>\n<p>(3) Add the keyword <code>intercept<\/code> to the <code>http_port line<\/code>. See below for explanation&lt;<\/p>\n<p><code class=\"block\">http_port 3128 intercept<\/code><\/p>\n<p>(4) Uncomment the directive that enables the proxy cache<\/p>\n<p><code class=\"block\">#cache_dir ufs \/var\/spool\/squid 100 16 256<\/code><\/p>\n<p>The third step is crucial since we are aiming to achieve inline proxy interception of all web traffic. Since the clients do not know they are sending their traffic through a proxy they are expecting to be dealing directly with the end webserver. The client proceeds as follows with obvious reduction of steps to the relevant ones:<\/p>\n<ul>\n<li>The user types http:\/\/www.google.com into the location bar and hits enter<\/li>\n<li>Obtain DNS for www.google.com<\/li>\n<li><code>GET \/<\/code> from www.google.com<\/li>\n<li>Squid intercepts the packet and attempts to perform a GET request on the URL \/, which is an invalid URL.<\/li>\n<\/ul>\n<p>If the client were knowingly configured to use a proxy, it would send the GET request as a proxy request (i.e. <code>GET http:\/\/www.google.com<\/code>). Placing the squid instance in <code>intercept<\/code> mode makes squid look at the <code>Host:<\/code> HTTP header. From this Squid can deride that it is supposed to perform a <code>GET<\/code> at www.google.com.<\/p>\n<h3>IPTables<\/h3>\n<p>The IPTables layer ends up being the work horse for this paradigm. It is here that all the traffic flow control occurs.<\/p>\n<p>The first step is to setup your default routing\/traffic control policy. In our case, we want to default deny any traffic being routed, except for a few exceptions of critical network services.<\/p>\n<pre class=\"block\"># Allow routing of established and related traffic, localhost and ping\r\niptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT\r\niptables -A FORWARD -i lo -j ACCEPT\r\niptables -A FORWARD -p icmp -j ACCEPT\r\n\r\n# Allow connections from the local network to squid\r\niptables -A INPUT -p tcp -s 10.10.48.0\/20 --dport 3128 -j ACCEPT\r\n\r\n# Allow LDAP, LDAPS, DNS\r\niptables -A FORWARD -p tcp --dport 389 -j ACCEPT\r\niptables -A FORWARD -p tcp --dport 636 -j ACCEPT\r\niptables -A FORWARD -p udp --dport 53 -j ACCEPT\r\n\r\n# Allow routing of web traffic to web registration application\r\niptables -A FORWARD -p tcp --dport 80 -d 10.10.24.63 -j ACCEPT\r\n\r\n# Default deny of all other routing\r\niptables -A FORWARD -j REJECT --reject-with icmp-port-unreachable<\/pre>\n<p>Next we want to setup the rules that will handle the redirection of unregistered machines&#8217; web browsers to the web registration application. We do this by using DNAT and rewrite the destination address to the DMZ side of the router.<\/p>\n<pre class=\"block\"># Network registration\r\niptables -t nat -A PREROUTING -i eth5 -p tcp --dport 80 -j DNAT --to-destination 137.143.24.63<\/pre>\n<p>As well, we need to setup a way for registered machines to be allowed through, but forced to pass HTTP traffic through the caching Squid proxy. We again will do this via NAT, but we will use a user-defined chain as well to tidy things up.<\/p>\n<pre class=\"block\"># Inline proxy redirection\r\niptables -N CACHE -t nat\r\niptables -A CACHE -t nat -p tcp --dport 80 ! -d 10.10.0.0\/16 -j REDIRECT --to-ports 3128\r\niptables -A CACHE -t nat -j ACCEPT<\/pre>\n<p>What we are saying here is if the HTTP traffic is not bound for a system on our network redirect it through Squid, otherwise accept it.<\/p>\n<h3>Web Registration Application<\/h3>\n<p>This part is up to the end-user to implement. We currently have an extensive tool set built that provides us this facility using Apache, Perl, and MySQL. Additionally we have a complete administrative interface that ties into it. At this point the world really opens up to what you are capable of creating. Regardless of implementation though, a registration event needs to achieve the following actions.<\/p>\n<ol>\n<li>Insert a rule in the <code>PREROUTING<\/code> chain before the DNAT rule for the client MAC address whose jump target is the <code>CACHE<\/code> chain<\/li>\n<li>Insert an <code>ACCEPT<\/code> rule into the <code>FORWARD<\/code> chain right before the default deny rule for the client MAC address<\/li>\n<\/ol>\n","protected":false},"excerpt":{"rendered":"<p>Using Linux, IPTables, Apache, Perl, MySQL, and Squid to create an in-line NAC content caching router. Background We currently utilize a network registration built upon the RFCs for how clients should deal with DNS servers. The idea being that we give out a bogus DNS server as the first one in the list in the [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"parent":16,"menu_order":0,"comment_status":"open","ping_status":"open","template":"","meta":{"jetpack_post_was_ever_published":false,"footnotes":""},"class_list":["post-595","page","type-page","status-publish","hentry"],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/P4mwGD-9B","_links":{"self":[{"href":"https:\/\/www.gregkuchyt.net\/index.php?rest_route=\/wp\/v2\/pages\/595","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gregkuchyt.net\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.gregkuchyt.net\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.gregkuchyt.net\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gregkuchyt.net\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=595"}],"version-history":[{"count":3,"href":"https:\/\/www.gregkuchyt.net\/index.php?rest_route=\/wp\/v2\/pages\/595\/revisions"}],"predecessor-version":[{"id":613,"href":"https:\/\/www.gregkuchyt.net\/index.php?rest_route=\/wp\/v2\/pages\/595\/revisions\/613"}],"up":[{"embeddable":true,"href":"https:\/\/www.gregkuchyt.net\/index.php?rest_route=\/wp\/v2\/pages\/16"}],"wp:attachment":[{"href":"https:\/\/www.gregkuchyt.net\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=595"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}