Sunday, 26 December 2010

Sharing internet connection through Wlan

I wanted to share my internet connection with my roomies using wireless LAN. I had done it using bridging in Windows; but I hardly use Windows. So, I needed a solution in linux. I started discussing about it on IRC. At #gentoo, I met a French guy, named Francis Galiegue, who gave me an elegant solution.

We have three laptops and the connection is through wired ethernet. So, the solution was to use one laptop (mine) as a wireless access point giving access to the internet. In this setup, it is granted that the laptop has network connectivity to the internet, and that it has a WiFi device (internal or external) recognised by linux and the kernel is recent enough (2.6.27 or later is recommended). Once you meet the prequisites, there are four parts, which are solved by four linux daemons elegantly:

0. without even configuring the WiFi device, check that the laptop can connect to the internet
1. setting up basic iptables rules (see rule set 1);
2. cooking up a set of rules so that the laptop can access the Internet via the appropriate device (see rule set 2);
3. configure a DHCP server (using dhcpd), complete the firewall rule set to allow it to work (see rule set 3);
4. configure a name server (using BIND), complete the firewall rule set to allow it to work (see rule set 4);
5. configure an access point (using hostapd) - and no, no firewall rules are necessary for the access point to operate (iptables operates at the network layer, hostapd operates below that level);
6. complete firewall configuration so that "client" computers (the other laptops) can actually connect to the Internet.

Rule set #1:

The goal here is to create a generic table which uses Linux's netfilter connection tracking abilities. Here we use the "state" module, which recognizes four states:
  1. ESTABLISHED: the incoming packet is part of a connection known toLinux' connection tracking;
  2. RELATED: the incoming packet either directly relates to, or establishes a new connection related to, a connection known to Linux's connection tracking - such packets are of two types:
    1. ICMP messages (such as: "no route to host", "access prohibited", others);
    2. connection triggers from builtin modules (such as FTP data connections, others);
  3. INVALID: the incoming packet has an invalid payload (header length and/or checksum mismatch at the network layer or upper);
  4. NEW: the incoming packet tries to initiate a new connection.
We create a new chain, named "connstate" (ie, "connection state"), attached to the "filter" table. The purpose of this chain will be to handle all four connection states known to the "state" module. Eventually, all packets, either incoming (INPUT), outgoing (OUTPUT) or going through (FORWARD) will go through this chain, except for the loopback interface (lo), which is special:

# Create the chain - note that by default, if the table (the -t option of
# iptables) is not specified, the default is filter - this is what we want
iptables -N connstate
# All packets of connections already known to netfilter's state tracking
# (ESTABLISHED) or directly related (RELATED) should pass
iptables -A connstate -m state --state ESTABLISHED,RELATED -j ACCEPT
# All packets deemed invalid by netfilter should be dropped
iptables -A connstate -m state --state INVALID -j DROP
# From then on, packets have to be NEW. One thing: if the packet is TCP and does
# not have the SYN bit set (which it should have, see RFC 793) should be
# dropped...
iptables -A connstate -m state --state NEW -p tcp ! --syn -j DROP
# Any other NEW packets are returned to the caller
iptables -A connstate -m state --state NEW -j RETURN
# Normally, no packet ever should reach this point, netfilter must/will have
# sorted them out earlier on. If not, this is clearly a bug, so log them at the
# highest log level avaibale (CRIT == critical), and drop them for safety.
iptables -A connstate -j LOG --log-level CRIT --log-prefix "CONNSTATE BARF: "
iptables -A connstate -j DROP
# There is one exception to the rules above: the loopback interface. Packets
# going through the loopback will not go through the normal chain processing,
# we need to accept them unconditionally at the input and output phase.
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
# From here on, the first thing to do is to make all packets of all builtin
# chains of the filter table go through this chain.
for i in INPUT OUTPUT FORWARD; do iptables -A $i -j connstate;done

At this stage, this chain enforces no restriction on incoming or outgoing traffic, except for two quite important things:
  1. no TCP and/or IP header fragmentation attack is possible anymore: as soon as you use connection tracking (as we do here), the firewalling engine must have all protocol headers to decide how to deal with the whole packet (attempted fragmentation attacks will be deemed INVALID and therefore DROPped);
  2. some stack implementations disobey RFC 793 with respect to TCP connection initiation, since they don't set the SYN bit on the initial TCP packet of the connection: these will be dropped as well (observed with some versions of Windows).

Rule set #2:

We proceed to allow ICMP (ping) traffic from the wifi interface.

iptables -N local_to_eth0
iptables -A local_to_eth0 -j ACCEPT
iptables -A OUTPUT -o eth0 -j local_to_eth0
iptables -N ping
iptables -A ping -p icmp --icmp-type echo-request -m limit --limit 2/sec -j ACCEPT
iptables -A ping -p icmp --icmp-type echo-request -m limit --limit 2/sec -j DROP
iptables -N eth0_to_local
iptables -A eth0_to_local -j ping
iptables -A INPUT -i eth0 -j eth0_to_local
for i in INPUT OUTPUT FORWARD; do iptables -P $i DROP;done

Rule set #3:

We proceed to allow ICMP (ping) traffic from the wifi interface.

iptables -N dhcp
iptables -A dhcp -p udp --dport 67:68 -j ACCEPT
iptables -N wlan0_to_local
iptables -A wlan0_to_local -j ping
iptables -A wlan0_to_local -j dhcp
iptables -A INPUT -i wlan0 -j wlan0_to_local

There are two ways of being a gateway:

  1. configure a dhcp server and bind
  2. use dnsmasq

We are using the former method here. So, you might want to query your package manager for dhcpd and bind to see whether they are installed.

Next, find out your domain name (hostname -f). Let us say your domain name is "domain_name". Now pick a hostname for your system, say "hostname.domain_name". You might opt for a two component domain name. Now, proceed to assign the selected hostname to your system. Pick an IP in RFC1918 range to assign to this name, say Edit /etc/hosts and add the following line: hostname.domain_name hostname

Now let us ensure that the hostname is assigned to the machine at boot time. It can be done by editting /etc/conf.d/net and /etc/conf.d/hostname in Gentoo linux or by editting /etc/rc.conf in Arch linux. (Set it to the full qualified hostname, i.e. "hostname.domain_name" not just "hostname".)

Next, we setup wlan0 with the address and a /24 subnet mask. It can be done using ifconfig as follows:

ifconfig wlan0 netmask

This can also be put into /etc/rc.conf so that it is done each time during boot. You may wish to cross check the IP of the wifi device. (See ifconfig ouput and try to ping the IP.)

Now, we configure the DNS server daemon, named. First of all, we are going to create two zone files: one for "domain_name" and the other for The file /var/named/pri/ is as follows:

$TTL 1d
@       IN      SOA     hostname.domain_name.  (
                                      2010102401 ; Serial
                                      28800      ; Refresh
                                      14400      ; Retry
                                      3600000    ; Expire
                                      86400 )    ; Minimum
              IN      NS

5 IN PTR hostname.domain_name.

Now, we edit the named.conf as follows:

// /etc/named.conf

acl "trusted" {;

options {
directory "/var/named";
pid-file "/var/run/named/";
auth-nxdomain yes;
datasize default;
// Uncomment these to enable IPv6 connections support
// IPv4 will still work:
// listen-on-v6 { any; };
// Add this for no IPv4:
// listen-on { none; };
listen-on {;;

// Default security settings.
allow-query {
allow-recursion {; };
allow-transfer { none; };
allow-update { none; };
version none;
hostname none;
server-id none;

forward first;
forwarders {
// The service provider's DNS first
      ;                // Level3 Public DNS
      ;                // Level3 Public DNS
      ; // Google Open DNS
      ; // Google Open DNS

view "internal" in {
match-clients { trusted; };
recursion yes;
additional-from-auth yes;
additional-from-cache yes;

zone "localhost" IN {
type master;
file "";
allow-transfer { any; };

zone "" IN {
type master;
file "";
allow-transfer { any; };

zone "." IN {
type hint;
file "root.hint";

zone "domain_name" {
type master;
file "pri/";
allow-update {
notify no;

zone "" {
type master;
file "pri/";
allow-update {
notify no;

logging {
        channel xfer-log {
                file "/var/log/named.log";
                print-category yes;
                print-severity yes;
                print-time yes;
                severity info;
        category xfer-in { xfer-log; };
        category xfer-out { xfer-log; };
        category notify { xfer-log; };

Now, lets start the server. On Arch, I do it using the following command.

/etc/rc.d/named start

We then edit /etc/resolv.conf.head to add the following line

search domain_name

and /etc/resolv.conf.tail to add the following line.


Now, the nameserver can be tested using commands like the following.

host hostname.domain_name

You might like to add named to the list of daemons to be started at boot time. I prefer starting them each time.

Rule set #4:

# create a new chain
iptables -N local_to_wlan0
# the only rule of this chain is to accept
iptables -A local_to_wlan0 -j ACCEPT
# In the OUTPUT chain, every packet going out by wlan0 interface is branched out to
# local_to_wlan0 and as a result everything out to wlan0 is accepted.
iptables -A OUTPUT -o wlan0 -j local_to_wlan0

The following iptables rules are to allow the other machines in the LAN to access the DNS server.
Bind listens to TCP/53 and UDP/53 and thus traffic on those ports is accepted.

Rule set #5:

iptables -N named
iptables -A named -p udp --dport 53 -j ACCEPT
iptables -A named -p tcp --dport 53 -j ACCEPT
iptables -A wlan0_to_local -j named

We proceed to configure the dhcp server. The configuration in /etc/dhcpd.conf is as follows:

# We don't want dynamic DNS here
ddns-update-style none;
subnet netmask {
option subnet-mask;
option domain-name "domain_name";
option domain-name-servers;
option routers;

pool {
allow unknown-clients;

Then we have a final set of rules to connect the two interfaces.

Rule set #6:

iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
iptables -N wlan0_to_eth0
iptables -A wlan0_to_eth0 -j ACCEPT
iptables -A FORWARD -i wlan0 -o eth0 -j wlan0_to_eth0

The last piece is hostapd configuration. It is given as follows:

wpa_passphrase=<your passphrase>

Each time I can start sharing using the following commands.

ifconfig wlan0 netmask
/etc/rc.d/iptables start
/etc/rc.d/hostapd start
/etc/rc.d/dhcpd start
/etc/rc.d/named start

For a rather detailed reading, check out this webpage.


totedati said...

well as an useful info when you are really so unfortunate to need such things, to provide wifi network acces for others using you main rig is to know this, but ...

is really, really such things like internet subscriptions from internet providers who do not use/provide dedicated wireless routers!? like my beloved router Asus RT-N16 powerhorse!?

with such a cheap rig, a dedicated wifi router, always on, you have wireless at you will for all neighborhood laptops ... a santa claus for all friends ...

between buying an usb wifi card and an dedicated wifi router will aways chose the router way ...

lyecdevf said...

I do not trust stock router firemware to offer good security. Maybe there are some products out there like the D-link DIR-655 extreme N wireless router that I thought was really neat but I got instead the wrt56gl and put on tomato firemware.

However, when I am going to get a bit better at linux I am going to set up a spare computer my self as a router. I believe that would offer much greater security than any router out there.

Phoenix said...

I agree on not trusting stock routers on security issues.