Problem solve Get help with specific problems with your technologies, process and projects.

Router Expert: Building a WLAN proxy server, implementing ASR

Using application service redirection (ASR) in the wireless LAN environment provides guest users enough information to be able to get access without the need for direct support.

In our last installment, Michael Martin continued his discussion of building a WLAN proxy server and explained how to implement Web Proxy Auto Discovery Protocol (WPAD).

Implementing application service redirection (ASR) in the WLAN environment makes guest access much easier. If you have ever used Internet access in a hotel, airport or coffee house, chances are you have experienced the "user" end of ASR. You may recall connecting to the hotel/airport network, launching your Web browser and instead of your home page coming up, a Web page instructing you what you need to do (asking for a CC# or room info) in order to get network access appears. If you wondered how they re-routed your Web request, this article is for you.

ASR in our WLAN environment
Annoying hotel and airport Internet access charges aside, ASR is cool from a security tool perspective. Not only does it afford you the ability to control access but also, perhaps even more importantly, it lets you inform your users about how they can get access -- a far more genteel approach for both users and the network support staff than simply blocking access. In our WLAN proxy server environment, ASR offers a bonus because it addresses a big support problem: how to get the users to use the proxy server for access.

You may recall that last month we looked at implementing WPAD so the WLAN users' Web browsers would be automatically configured to use the http proxy server. After all if the users don't use the proxy server, it's not a very effective security solution. Now, if you recall the article, you will also recall that WPAD is not perfect. WPAD is far better than nothing at all. But the fact remains that many users and many corporate security policies disable the WPAD function in their Web browsers. This is done mainly for two reasons. First, the WPAD discovery process slows the Web browser launch cycle, especially on Internet Explorer. Second, proxy servers log Web transactions. Since WPAD will passively configure a Web browser to use a proxy server, a user's Web activity would be logged without them knowing it. To avoid that possibility, WPAD is disabled.

However, in our secure WLAN environment, you need to use the http proxy server to get network access. No proxy, no access. So instead of answering support calls, we can implement WPAD and ASR in combination. Browsers configured to support WPAD will work straightaway. Browsers that are not will have their transactions ASRed to a policy Web page and be instructed on how to access the proxy by either enabling WPAD or manually configuring their Web browser. Here is a Web page example of what users can get when they attempt non-proxy Web access:

For our WLAN environment, the goal is to use ASR to provide the users enough information to be able to get access without the need for direct support. The page above gives users what they need to configure their browsers correctly and obtain access. Alternatively, if your security requirements are a bit stricter, ASR can strictly inform users about who to contact for support, how to obtain access credentials, etc. Regardless of your network policy, ASR provides a way to directly inform users of how to access the network through a familiar interface. The added bonus of potentially reduced support load is always a good thing.

Building the ASR environment
Building the ASR environment involves three task areas. First, a means for redirecting the users' network transactions needs to be configured. Second, a gateway that can handle the actual transaction hijacking has to be built. The third task involves implementing "servers" that can respond to the redirected transactions. Our implementation will cover the following:

  • Using Cisco IOS policy routing and SAA
  • Using Linux netfilter and iptables
  • Using rinetd Internet redirection server
  • Using mini-httpd lightweight Web server

Implementing Cisco policy routing
Policy-based routing (PBR) allows network administrators to build traffic handling rules for specific types of network traffic. For example, let's say I want the router to send all http traffic through one IP gateway and all the other traffic through another. Or, perhaps all traffic from the network is forwarded out of ISP gateway A and all the other subnets are forwarded out of ISP gateway B, and in the event that ISP gateway A is down, everything is sent through ISP B. The ability to add Boolean logic to routing decisions is a major win for network administrators.

However, there is a price for this awesome power. Policy routing is handled in software, so you need to have a router with enough CPU to handle the policies you want implement. While powerful, Cisco's early implementation of PBR was limited in its ability to recover when network outages would occur. Starting in Cisco IOS 12.3 T, Service Assurance Agent (SAA) support was added to policy routing. This addition makes its possible to use "if then, else" policy statements that can handle network outage events. Our example will utilize this feature, so IOS 12.4 or later is required. Here is a diagram for our example network:

Our example configuration will configure the router to redirect http, SSH, Telnet, and ftp network traffic to the redirection server. In the event that the redirection server is not available, the router will forward the traffic to the upstream router. In our WLAN environment we want to ensure the security of the segment; so logging could be maintained we would typically want the traffic to be dropped. That said, to maintain the security posture a secondary proxy server could be implemented or you may have a policy that simply ensures that users have connectivity. In either case, an example illustrating a secondary path option seems more appropriate. Here are the configuration steps:

1. Create a traffic qualifier access control list (ACL) for the policy route:

 outlan-rt03(config)#access-list 101 permit tcp any any eq www

2. Create SAA response time reporter (RTR) operation objects:

outlan-rt03(config)#rtr 1
outlan-rt03(config-rtr)#type echo protocol ipicmpecho
outlan-rt03(config)#rtr 2
outlan-rt03(config-rtr)#type echo protocol ipicmpecho

3. Enable the RTR using the configuration command <rtr schedule {rtr obj #} life {forever | seconds} start time {options}>:

outlan-rt03(config)#rtr schedule 1 life forever start-time now
outlan-rt03(config)#rtr schedule 2 life forever start-time now

4. Create the tracking object's using the configuration command <track {track obj #} rtr {rtr obj #} reachability>:

outlan-rt03(config)#track 1 rtr 1 reachability
outlan-rt03(config)#track 2 rtr 2 reachability

At this point, we have created two RTR SAA objects and have enabled them. We have also created two tracking objects that monitor the RTRs. The route map "action" statements then utilize the SAA tracking agents. They provide data on availability, which determines if the action statement is viable. Now, let's create the policy route.

Create route-map for the policy route:

outlan-rt03(config)#route-map http-redirect-80 permit 10
outlan-rt03(config-route-map)#match ip address 101
outlan-rt03(config-route-map)#set ip next-hop verify-availability 10 track 1
outlan-rt03(config-route-map)#set ip next-hop verify-availability 20 track 2

Install the policy route on the router's interface:

outlan-rt03(config)#interface FastEthernet0/0
outlan-rt03(config-if)# ip policy route-map http-redirect-80

Check the SAA tracking objects using the exec command <show track>:

outlan-rt03#sh track
Track 1
  Response Time Reporter 1 reachability
  Reachability is Up
    11 changes, last change 3d00h
  Latest operation return code: OK
  Latest RTT (millisecs) 1
  Tracked by:
Track 2
  Response Time Reporter 2 reachability
  Reachability is Up
    1 change, last change 3d01h
  Latest operation return code: OK
  Latest RTT (millisecs) 1
  Tracked by:

Check the policy route using the exec command <show route-map>:

outlan-rt03#sh route-map 
route-map http-redirect-80, permit, sequence 10
  Match clauses:
    ip address (access-lists): 101 
  Set clauses:
    ip next-hop verify-availability 10 track 1  [up]
    ip next-hop verify-availability 20 track 2  [up]
  Policy routing matches: 113 packets, 8798 bytes

Now that our policy is built, let's quickly review how our routing policy will work when the server is up.

The user will open (1) a standard http request. The router will accept the packet (2), inspect it and forward it to the redirection server. The redirection server (3a) will accept the request, pass it on to an information server and respond with a block warning or information page. In the event that the proxy server becomes unavailable, (3b) the router will then forward the request to the normal upstream gateway.

Implementing redirection gateway
The policy route gets the traffic to the redirection gateway. The redirection gateway then gets the traffic to the information server. It's this server in the middle, the redirection gateway, where all of the ASR magic happens. But to make the magic happen, we need to solve two problems. First, IP hosts do not typically respond to "server" level requests that are not directly intended for them. Second, how do you even get a host to accept "server level" traffic that is not directly intended for it? Chances are, if you have two problems, you will need two solutions. So, redirection gateway is made up of two components: rinetd and the Linux netfilter/iptables firewall. Rinetd handles the first problem of getting a server to respond to traffic that's not meant for it. Then netfilter/iptables firewall handles the problem of getting traffic that's not meant for the server to the server in the first place.

Normal operation of a TCP-based service has a one (or more) network interface with a unique IP address and a single unique services port allocated for each network service running on a node. While it's possible to have multiple service ports associated with an IP address, each network service daemon has its own unique service port assigned to it. These unique service numbers are standardized as http (80), ftp (21), etc. This way clients need only know the IP address of the server they wish to connect to. The service port is uniform across all servers and for each different network service. Each network server daemon running on a server listens on the service port for incoming transactions.

In order to get a typical client-server connection established, two criteria must me met. First, the client host opening the session must send an IP packet with its source IP address (so a reply may be sent) and the destination IP address that matches with the IP address for which the server is configured to accept requests. Second, the TCP header within the IP packet must connect to the service port for which the server is configured to accept requests. If either of these two elements is missing, no connection can be established.

ASR operates by taking connection requests for random servers from random hosts and directing them all to a single server. The clients who make these requests expect replies from the servers they sent them to. If the replies do not come from the requested hosts (or at least appear to from an IP and port perspective), the hosts will drop any replies.

At first glance, this sounds like problem that can be solved using Network Address Translation (NAT). You could use a model that looks something like this diagram:

User A opens a connection to the server through B. IP Address B is a proxy address for the actual server D; it opens a proxy connection using address C. The actual server address D responds to host A's request through the proxy address C. The proxy server then sends the server's reply to host A using its B interface. This works great, if you can set up all of this static mapping. But our criteria require NAT from "any" to "any," but ending up a specific IP address.

That's where rinetd comes in. Rinetd was originally developed to do service level NAT. It can listen for http requests on address, but then send them to address and make it appear as if the host was communicating with the whole time. What makes rinetd great is that not only can the daemon do one-to-one NAT translations; it can also do any-to-one NAT translations. That is just what we need to do. So let's get it built and installed, and then we will move on to the other half of the redirector netfilter/iptables.

The build and install process for rinetd is quite simple:

1. Get the server source code:

[[email protected] root]# wget
           => `rinetd.tar.gz'
Resolving done.
Connecting to[]:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 115,541 [application/x-tar]

100%[====================================================>] 115,541      333.83K/s    ETA 00:00
20:15:12 (333.83 KB/s) - `rinetd.tar.gz' saved [115541/115541]
[[email protected] root]# 

2. Expand the source code tall ball:

[[email protected] root]# tar xvfz rinetd.tar.gz 
[[email protected] root]# 

3. Move into the build directory; compile and install the binary:

[[email protected] root]# cd rinetd
[[email protected] rinetd]# make
cc -DLINUX -g   -c -o rinetd.o rinetd.c
cc -DLINUX -g   -c -o match.o match.c
gcc rinetd.o match.o -o rinetd
[[email protected] rinetd]# make install
install -m 700 rinetd /usr/sbin
install -m 644 rinetd.8 /usr/man/man8
[[email protected] rinetd]# 

Once the binary is installed, we need to build the configuration file, which we will get into shortly. Rinetd looks for the configuration file in the servers /etc directory. Typically, rinetd is loaded at boot and remains up. Changes to the configuration file are not applied unless the service is restarted. Here is a simple control script that lets you easily start, check run status, stop, or reload the rinetd service.


touch /var/tmp/rinetd-pid.test


if [ "$1" = "-h" ]
echo "

        CLI Options
        -h = display help
        -k = stop rinetd
        -r = restart rinetd  

        No option, the server checks to see if it's running
        if not it starts.


# Kill rinetd
if [ "$1" = "-k" ]
kill -9 `cat /var/run/`;echo "service stopped";exit

# Restart rinetd
if [ "$1" = "-r" ]
kill -HUP `cat /var/run/`;echo "restarted...";exit

# Check to see if rinetd is running, if not start it.

ps -aux | grep `cat $PID` | awk '{print $2}' | sed '$d' > $PIDTEST

if [ `cat $PID` = `cat $PIDTEST` ]
echo "were running"

The script can run as part of the bootstrap process, called from /etc/rc3.d/S99lLocal. Run from CRON or just run from the CLI.

With rinetd, we can now service any request from any host to any server with a reply from our information server. Here is a packet trace of a host requesting a connection to (

20:49:25.666822 IP (tos 0x0, ttl  64, id 10337, offset 0, flags [DF], proto: 
TCP (6), length: 458) > P, cksum 0x204b (correct), 1:407(406) ack 1 win 65535 
<nop,nop,timestamp 804418056 60354685>
E...([email protected]@.....P-.......P6.4.s....... K.....
/.r....}GET / HTTP/1.1
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv: 
Gecko/20061204 Firefox/
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive

And the first packet from the response from ( to our information server via rinetd:

20:49:25.668852 IP (tos 0x0, ttl  64, id 28073, offset 0, flags [DF], proto: TCP
 (6), length: 1460) 
> ., cksum 0xa4ee (correct), 224:1632(1408) ack 407 win
 6432 <nop,nop,timestamp 60354685 804418056>
[email protected]@.v|......P-.P..s...6.6A... .......

<META HTTP-EQUIV="Expires" CONTENT="-1">che">eb 1997 08:21:57 GMT">

                <title>Welcome to cell</title>

server account.</p>[email protected]">[email protected]</a> for a proxy

considered a security violation is strictly prohibited and may be

officials of criminal activity, evidence of such activity to law enforcement

of capturing other visitors traffic is strictly tools for the purpose

Now that we know how rinetd works, we move on to the other problem. How do we get all of those transactions to rinetd? The policy route sends the IP packets with the server requests to the redirection server. But each of these requests still has a "remote" destination address. We need to force the packets to the service port to which rinetd is listening in order for it to "service" the requests. That's where netfilter and iptables enter the stage.

But netfilter, iptables and the information server configuration are all for next month. So stay tuned.

This was last published in January 2007

Dig Deeper on Wireless LAN (WLAN)