Setup your own Linux router using iptables – Part 1

When using Linux on servers we all know that one basic tool to secure the setup is iptables. Iptables not only allows you to secure your setup, it will also allow you create a routing service in a very controlled and efficient way.router_hw_example

Every distribution has it’s how way to configure and deploy the desired set of rules, Ubuntu and it’s variants use ufw service, Redhat and it’s clones iptables service, OpenSuSE uses SuSEfirewall2 service, etc.

To be honest my preferred way of managing is the Redhat style. It’s cleaner, doesn’t have hidden features and it doesn’t try to make it easier for the user. Although some of those functions may seam good in the long run they may become limitations.

So, why not make your own custom iptables startup script and iptables rule set that will be compatible with most of Linux distributions? This blog post will focus in two distinct areas:

  1. Create an init script to enforce our iptables rule set
  2. Create a set of iptables rules that could be put in place on a Linux gateway

Assumptions:

  1. You have ip_forwarding enabled on your system (if not you may check this link)
  2. You have a mainstream Linux distro with iptables and it’s most used modules (like conntrack)
  3. You have root access to the Linux GW
  4. I’m using OpenSuSE 13.1 x86_64, nevertheless this guide should work on other distributions only with minor changes on configuration variables

Lets start by defining the scope of the rule set, the example scenario will be (the IPs were randomly selected) one Linux box serving as gateway for three networks):

  • eth1 172.17.31.0/29 – lets call it orange and use it as DMZ (we will have the server providing external services in this network)
  • eth2 192.168.9.0/24 – lets call it green and use it as users networks, having some servers on the subnet 192.168.9.0/9, we also want to give VPN users to this subnet
  • tun0 10.238.23.1/28 – lest call it blue and use it for VPN access

In the examples we use different network cards but it can also be done with VLANs and/or with a plain network interface having all the logic based on src/dst IPs, ports and protocols.

On the Internet access interface (eth0, we may call it red) we will have 6 usable IP addresses 21.32.181.1-6. These IPs will be exposed to the Internet.

On those six available IP addresses we will want different services also exposed to the Internet, the network address translation table will be:

  • 21.32.181.1 port 53 -> 172.17.31.1 port 53 (udp)
  • 21.32.181.1 port 53 -> 172.17.31.1 port 53 (tcp)
  • 21.32.181.2 port 80 -> 172.17.31.2 port 80 (tcp)
  • 21.32.181.3 port 443 -> 172.17.31.3 port 443 (tcp)

Apart from the NAT table we will also make sure that:

  • Access to other destination IP/port/protocol combination will be denied
  • The default gateway to access the wan will be 21.32.181.6

In this example we won’t talk about having more than one gateway, although it’s easily achievable.

Finally we won’t allow internal IP traffic to access the Internet freely (we all know how dangerous it is :)), so  we will limit the access to the following ports/protocols:

  • TCP: 25,80,110,144,443,465,993
  • UDP: 53,1194
  • ICMP: type 8

Please note that this doesn’t limit the access from our Linux GW to the Internet, it will be applied on the forward chain so the effect will only be visible on the clients using our Linux GW as their GW. The Linux GW will have complete access to all the networks, including unfiltered access to the Internet.

Bellow is a diagram about how the network should like:


        ------------         ---------------------------------------
        |          |         | Linux GW:                           |
        | Internet |---------| Ext net (eth0): 21.32.181.1/29  *   |
        |          |         | Int net (eth1): 172.17.31.14/28     |
        ------------         | Int net (eth2): 192.168.9.254/24    |
                             | VPN net (tun0): 10.238.23.14/28     |
                             ---------------------------------------
                              /               |                \
           output            /          input |    output       \  output
          (Internet/        /      everywhere |   (to Internet)  \(to orange / Internet)
            orange)        /      to services |                   \
                ----------------         ------------        ----------------
                   green                   orange                       blue
          192.168.9.0/24                172.17.31.0/28                  10.238.23.0/28
                                        172.17.31.1/28 - udp 53
                                        172.17.31.2/28 - tcp 80
                                        172.17.31.3/28 - tcp 443

* the external network includes all the IPs between 21.32.181.1 - 21.32.181.6

Lets get back to the first target on this blog post: Create an init script.

Please create a file named pmso-fw (in reality you can name it whatever you like) in /etc/init.d

#!/bin/bash
# PMSO fw initializer
#
# pmso-fw:   Pedro Oliveira FW builder
#
# chkconfig: 345 03 03
# description:  This is a daemon for managing firewall scripts \
#               config file should be located in \
#               /etc/sysconfig/iptables
#
# notes:        please set rc.status according to your OS / Distro
# processname: pmso-fw
# pidfile: /var/run/pmso-fw.pid
#

. /etc/rc.status
rc_reset

SERVICE="pmso-fw"
IPT4="/usr/sbin/iptables"
PROCESS_APPLY="/usr/sbin/iptables-apply"
CONFIG_FILE="/etc/sysconfig/iptables"
LIST_RULES="/usr/sbin/iptables-save"
PIDFILE="/var/run/pmso-fw.pid"

test -f $CONFIG_FILE

start() {
  stop
  sleep 3650d &
  echo $! > $PIDFILE
  echo -n $"Starting $SERVICE "
  `$PROCESS_RESTORE < $CONFIG_FILE`
  RETVAL=$?
  rc_status -v
}

stop() {
  echo -n $"Stopping $SERVICE "
  $IPT4 -F && \
  $IPT4 -X && \
  $IPT4 -t nat -F && \
  $IPT4 -t nat -X && \
  $IPT4 -t mangle -F && \
  $IPT4 -t mangle -X && \
  $IPT4 -P INPUT ACCEPT && \
  $IPT4 -P FORWARD ACCEPT && \
  $IPT4 -P OUTPUT ACCEPT
  RETVAL=$?
  rc_status -v
}

restart() {
  stop
  start
}

stat() {
  $LIST_RULES
  RETVAL=$?
  rc_status -v
}

# See how we were called.
case "$1" in
  start|stop|restart)
    $1
  ;;
  status)
    echo -n "Checking status of $SERVICE "
    rc_status -v
  ;;
  *)
    echo $"Usage: $0 {start|stop|status|restart}"
    rc_failed 2
    rc_exit
  ;;
esac
rc_exit

Lets describe what this script does:

  1. The first section look a regular comment section, nevertheless it’s in this zone that are configured the systemd options. Be careful if editing
  2. /etc/rc.status – this line means that the /etc/rc.status file will be imported, this file contains the systemd control functions
  3. General script configs and main utilities location section
  4. Script functionality functions:
  5. start() – The start function starts with stop, this may seam odd but if we are starting the FW service we want to guarantee that no rules will be duplicated. I also issue a sleep command, this is due to the fact that iptables isn’t a process and we need to keep the process open so we have a clean process status
  6. stop() – The stop function cleans all the tables
  7. restart() – No explanation needed
  8. stat() – Stat will use the systemd functions to return the status of the fw rules

We also need to make the script executable:

chmod u+x /etc/init.d/pmso-fw

Now you should create the systemd config file IF you use systemd. The file should be placed in: /etc/systemctl/system/pmso-fw.service and it will have the following content:


[Unit]
Description=PMSO-FW
After=network.target
Wants=network.service

[Service]
ExecStart=/etc/init.d/pmso-fw start
ExecStop=/etc/init.d/pmso-fw stop
RemainAfterExit=true
Type=oneshot

[Install]
WantedBy=multi-user.target

Finally lets setup the rule set.
The format of the this rule set is compatible with iptables-save and iptables-restore

The location of the file will be: /etc/sysconfig/iptables

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:LOG-INPUT - [0:0]
:LOG-FORWARD - [0:0]
:LOG-BLUE-TO-GREEN - [0:0]
:LOG-GREEN-TO-BLUE - [0:0]
:RED-TO-ORANGE - [0:0]
:BLUE-TO-ORANGE - [0:0]
:BLUE-TO-GREEN - [0:0]
:GREEN-TO-ORANGE - [0:0]
:GREEN-TO-BLUE - [0:0]
:TO-RED - [0:0]
:TO-GREEN - [0:0]
:TO-ORANGE - [0:0]
:T0-BLUE - [0:0]
:FROM-RED - [0:0]
:FROM-GREEN - [0:0]
:FROM-ORANGE - [0:0]
:FROM-BLUE - [0:0]
###

-A LOG-INPUT -j LOG --log-prefix "IPTables-reject-INPUT: "
-A LOG-FORWARD -j LOG --log-prefix "IPTables-reject-FORWARD: "
-A LOG-BLUE-TO-GREEN -j LOG --log-prefix "IPTables-reject-BLUE-TO-GREEN: "
-A LOG-GREEN-TO-BLUE -j LOG --log-prefix "IPTables-reject-GREEN-TO-BLUE: "
###

-A INPUT -i lo -j ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -m limit --limit 2/sec -j ACCEPT
-A INPUT -d 172.17.31.14 -p tcp -m tcp --dport 22 -j ACCEPT -m comment --comment "Access to the SSH interface only on the DMZ interface"
-A INPUT -m limit --limit 2/sec -j LOG-INPUT
-A INPUT -m limit --limit 2/sec -j LOG-INPUT
-A INPUT -j REJECT --reject-with icmp-port-unreachable
###

-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i eth1 -o eth0 -s 172.17.31.0/28 -j TO-RED
-A FORWARD -i eth2 -o eth0 -s 192.168.9.0/24 -j TO-RED
-A FORWARD -i tun0 -o eth0 -s 10.238.23.0/28 -j TO-RED

-A FORWARD -o eth1 -d 172.17.31.0/28 -j TO-ORANGE
-A FORWARD -o eth2 -d 192.168.9.0/24 -j TO-GREEN
#-A FORWARD -o tun0 -d 10.238.23.0/28 -j TO-BLUE

-A FORWARD -i eth1 -s 172.17.31.0/28 -j FROM-ORANGE
-A FORWARD -i eth2 -s 192.168.9.0/24 -j FROM-GREEN
-A FORWARD -i tun0 -s 10.238.23.0/28 -j FROM-BLUE

-A FORWARD -i tun0 -s 10.238.23.0/28 -o eth2 -d 192.168.9.0/24 -j BLUE-TO-GREEN
-A FORWARD -i tun0 -s 10.238.23.0/28 -o eth1 -d 172.17.31.0/28 -j BLUE-TO-ORANGE
-A FORWARD -i eth2 -s 192.168.9.0/24 -o eth1 -d 172.17.31.0/28 -j GREEN-TO-ORANGE

-A FORWARD -i eth1 -o eth1 -j ACCEPT
-A FORWARD -i eth2 -o eth2 -j ACCEPT
-A FORWARD -i tun0 -o tun0 -j ACCEPT

-A FORWARD -m limit --limit 2/sec -j LOG-FORWARD
-A FORWARD -j REJECT --reject-with icmp-port-unreachable
###

-A BLUE-TO-GREEN -d 192.168.9.0/29 -j ACCEPT
-A BLUE-TO-GREEN -m limit --limit 2/sec -j LOG-BLUE-TO-GREEN
-A BLUE-TO-GREEN -j REJECT --reject-with icmp-port-unreachable

-A BLUE-TO-ORANGE -j ACCEPT

-A GREEN-TO-ORANGE -j ACCEPT

-A GREEN-TO-BLUE -m limit --limit 2/sec -j LOG-GREEN-TO-BLUE
-A GREEN-TO-BLUE -j REJECT --reject-with icmp-port-unreachable

-A TO-RED -p icmp -m icmp --icmp-type 8  -j ACCEPT
-A TO-RED -p tcp -m multiport --dports 25,80,110,144,443,465,993 -j ACCEPT
-A TO-RED -p udp -m multiport --dports 53,1194 -j ACCEPT

COMMIT
###

*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]

-A PREROUTING  -d 21.32.181.1 -p udp --dport 53 -j DNAT --to-destination 172.17.31.1:53
-A PREROUTING  -d 21.32.181.1 -p tcp --dport 53 -j DNAT --to-destination 172.17.31.1:53

-A PREROUTING  -d 21.32.181.2 -p udp --dport 53 -j DNAT --to-destination 172.17.31.1:53
-A PREROUTING  -d 21.32.181.2 -p tcp --dport 53 -j DNAT --to-destination 172.17.31.1:53

-A PREROUTING  -d 21.32.181.3 -p tcp --dport 80 -j DNAT --to-destination 172.17.31.2:80
-A PREROUTING  -d 21.32.181.3 -p tcp --dport 443 -j DNAT --to-destination 172.17.31.3:443

-A POSTROUTING -o eth0 -j MASQUERADE

COMMIT
###

*mangle
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
COMMIT

Now that we have the files ready we need to setup our newly created installation script, this can be done with the following commands if you use systemv:

insserv /etc/init.d/pmso-fw (if you use systemv)
/etc/init.d/pmso-fw status

or if you use systemd

systemctl daemon-reload
systemctl enable pmso-fw # to make it permanent
systemctl start pmso-fw # to start it

you’ll be able to check the status of the fw with:

systemctl status pmso-fw

if you want to see the rules in use at any given moment you may use:

iptables-save

or

iptables -n -L --line-numbers
iptables -n -L -t NAT --line-numbers

After editing the rules you can also reload the service with:

systemctl restart pmso-fw

As you might have noticed we log the dropped packets, not all because if we have an exposed router the log will be immense but we limit the writes to two entries per second. This will allow us to debug something that isn’t right on our configuration but won’t fill our log file system or root partition (depending on how you partitioned your system).

In OpenSuSE 13.1 you may check your logs in “/var/log/firewall”.

On the next post we will get into more detail on the rules, detailing what’s done on the main blocks of the iptables rule set. I hope you have as much fun adapting this how to to your needs as I had making it.

Regards,
Pedro M. S. Oliveira

Share

Wildcard DNS in your Ubuntu hosts file using dnsmasq

Today we are going to add a wildcard DNS entry to our systems DNS resolver, to allow for easy local web application development (on Ubuntu 12.04). So, if we have a project called “LeaseWebLabs” that is (or will be) hosted on http://www.leaseweb.com/labs, we might want to develop it on http://www.leaseweblabs.dev. To achieve this we need to change the DNS resolving (resolving = hostname to IP address conversion) of specific hostnames. We want to achieve that anything ending with “.dev” resolves to the IP address 127.0.0.1 (which is the localhost).

Goal: *.dev ==[resolves-to]==> 127.0.0.1

Before we go into the details, let me give you an overview of the applications involved. The applications and/or files that have a part in DNS resolving (on Ubuntu) are:

  1. /etc/hosts (this file is used to override the resolver)
  2. network-manager (the network icon on your desktop)
  3. dnsmasq-base (local resolver, installed by default, unconfigurable)
  4. dnsmasq (full configurable version that can be added manually)
  5. resolvconf (manages the contents of the file “/etc/resolv.conf”)
  6. avahi-daemon (a.k.a. ZeroConf or Bonjour, this uses .local)
  7. apache2 (the webserver needs to respond to the .dev hostname)

Long instructions

You can add “127.0.0.1 leaseweblabs.dev” to your “/etc/hosts” and the problem is solved. Easy right? This works, but it is NOT possible to have a wildcard DNS entry in the ‘hosts’ file. This means you will have to update the ‘hosts’ file for every hostname you want to use. This can be a problem when your web application works with dynamically generated subdomains. Fortunately, there is a workaround.

To understand the workaround we first need to understand how Ubuntu does DNS resolving. From version 12.04 onward, it uses the “dnsmasq-base” package to do DNS resolving, which is started by the “network-manager” service. This base version does not allow you to use a “/etc/dnsmasq.conf” file for configuring and will just serve the contents of the “/etc/hosts” file (and rules added by the network manager).

Wildcard DNS entries are possible in the dnsmasq config file “/etc/dnsmasq.conf”. The format of the wildcard entries in “/etc/dnsmasq.conf” is “address=/dev/127.0.0.1”, where “dev” is the wildcard domain (e.g. *.dev). You should try to avoid running an open resolver and add the line “listen-address=127.0.0.1” and “bind-interfaces”. Note that you should not use “.local”, since avahi-daemon is using that. You can make it work, but it will be slower, since ZeroConf (mdns) has to check your local network for devices first.

To disable the non-configurable dnsmasq-base, we can simply comment out the line “dns=dnsmasq” in “/etc/NetworkManager/NetworkManager.conf”. Next we can install the full dnsmasq using “sudo apt-get install dnsmasq”. Note that it won’t start because the old dnsmasq is still running. When you want to start using the full dnsmasq it will complain that it failed to create a listening socket, like this:

dnsmasq: failed to create listening socket: Address already in use

Now we can find the process-id of dnsmasq (base) and kill it using the word kill and the process-id.

NB: Your process-id will be different.

maurits@nuc:~$ sudo netstat -plant | grep :53
tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN      3101/dnsmasq
maurits@nuc:~$ sudo kill -9 3101

Now restart the dnsmasq service using “sudo service dnsmasq restart” to start the full dnsmasq without any problems. Now to make sure your connections will use your new resolver, you must make sure it is added to network connections. You do this by adding the “prepend domain-name-servers 127.0.0.1;” line to “/etc/dhcp/dhclient.conf”. After that you have to disconnect and reconnect all connections (also wired) or restart the network manager (which does the same) using “sudo service network-manager restart”. Now when you click on “Connection Information” in the network manager menu you should see that “Primary DNS” is set to “127.0.0.1”.

NB: It is important you configure Apache to respond to the new “.dev” hostname in its virtualhost configuration. In our case we changed the servername to “ServerName leaseweblabs.dev” in “/etc/apache2/sites-available/leaseweblabs”. After modifying this you need to reload apache2 with “sudo service apache2 reload”.

Debugging

By default, dnsmasq will look for upstream DNS servers when resolving. To debug this solution you may want to uncomment “#log-queries” in “/etc/dnsmasq.conf” and see in real-time what is happening using “tail -f /var/log/syslog”. You can also type “cat /run/resolvconf/interface/NetworkManager” at any time, to see what effective list of resolvers is being used. To force an update of the resolver configuration you can execute “resolvconf -u”, but this is normally not needed.

Use “dig leaseweblabs.dev” or “telnet leaseweblabs.dev 80” and do the same with a public website: “dig google.com” or “telnet google.com 80”. If there are answers to the “dig” requests and telnet connects successfully, you should probably be looking at your virtual host configuration.

Short instructions

$ sudo nano /etc/NetworkManager/NetworkManager.conf
- search for "dns=dnsmasq"
- replace with "#dns=dnsmasq"
$ sudo apt-get install dnsmasq
$ sudo nano /etc/dnsmasq.conf
- append line: "listen-address=127.0.0.1"
- append line: "bind-interfaces"
- append line: "address=/dev/127.0.0.1"
$ sudo netstat -plant | grep :53
- look for "NUMBER/dnsmasq"
$ sudo kill -9 NUMBER
- fill in the number you found for "NUMBER"
$ sudo service dnsmasq restart
$ sudo nano /etc/dhcp/dhclient.conf
- append line: "prepend domain-name-servers 127.0.0.1;"
$ sudo service network-manager restart

Did you try this, but you didn’t succeed? Do you have improvements? Let me know!

Share

Stream Spotify via Airplay to your Linux HTPC

Today we will show you how to setup your Linux HTPC as AirPlay target so that you can stream music services like Spotify from your iPhone or iPad to it. A Home Theater PC (HTPC) or Media Center computer is a PC connected to a TV and/or audio system that supports video, photo, audio playback, and sometimes video recording (PVR) functionality.

Spotify is a commercial music streaming service providing DRM-protected content from a range of major and independent record labels, including Sony, EMI, Warner Music Group and Universal. Today (June 21st 2013) Spotify is available in: Australia, Austria, Belgium, Denmark, Finland, France, Germany, Netherlands, New Zealand, Norway, Spain, Sweden, Switzerland, UK, US, Ireland, Andorra, Liechtenstein, Monaco, Luxemburg. It has very nice “app” for the iPad or iPhone to select and play music.

Alternatives to Spotify are:


If you have both a Linux HTPC and a (paid) Spotify premium account you can combine them into an awesome entertainment system. The convenient part is that you will use your iPhone/iPad to choose music that will be streamed over the Wifi using the AirPlay protocol to your HTPC and then to your sound system. I assume your home network/living room setup looks like this:

shairtunes_network

What we are going to do is add a service to the HTPC that allows us to play music on the stereo system. We are going to be using the AirPlay protocol that is created by Apple and allows you to play stream audio from an Apple device towards speakers or a stereo line-out. The first device to support AirPlay protocol was the AirPort express home Wifi router by Apple. Nowadays you can get a really cool portable speaker or regular speaker with Wifi support that allow you to stream directly to them using the AirPlay protocol.

Even if you are very Linux minded it could happen that you get an iPhone from your boss. In that case you might not be willing to invest in Apple (related) products like the speakers mentioned above. What you can do is install “shairport”: a software package that allows your free Linux machine to behave like an AirPlay target. This way you can enjoy music from your iPhone on your speakers via your Linux HTPC. You need to install the dependencies, download the code, compile and install it. This sounds like a lot of work, but it is actually not that hard:

sudo apt-get install build-essential libssl-dev libcrypt-openssl-rsa-perl libao-dev libio-socket-inet6-perl libwww-perl avahi-utils pkg-config
sudo cpan install HTTP::Request HTTP::Message Crypt::OpenSSL::RSA IO::Socket::INET6 Net::SDP
wget https://github.com/abrasive/shairport/archive/master.zip
unzip master.zip
cd shairport-master/
make
perl shairport.pl
sudo make install

Now all you need to do is start the “shairport” service and you are ready to enjoy your new audio setup:

sudo /etc/init.d/shairport restart

Enjoy the music!

Share

DD-WRT in Repeater Bridge mode

ddwrt

DD-WRT is a third party developed firmware, released under the terms of the GPL for many ieee802.11a/b/g/h/n wireless routers based on a Broadcom or Atheros chip reference design. — DD-WRT wiki

Today we are discussing DD-WRT and specifically how you can do some cool stuff that you would not be able to do with your current wireless router. Chances are that your home router is compatible with DD-WRT. You can find this out by checking the DD-WRT router database. With DD-WRT firmware loaded, your router is able to do some tricks it might not be able to do before. One of these things might involve the repeater bridge mode, which can improve your WiFi range at home. Since devices are automatically switching between WiFi and 3G, especially since the 3G prices (in the Netherlands) are quite high and/or low data traffic limits apply, this mode is a necessity.

So what is the plan? Let’s assume you have a living room with an (non wireless) Internet modem, a server, a printer and a laptop. In your study you have another three PC’s. You need a Mac, a Windows PC and a Linux computer right? Occasionally you bring your laptop from the living room. Let’s assume your wife (or husband) did not allow you to put a nice fast gigabit cable connection between your living room and the study, because he/she feels the cables do not match the interior design. Obviously there is no arguing and you need to go wireless. The fastest wireless connections you get now follow the N standard with a theoretical maximum of 300 Mbps. In reality you will probably only get a fraction of that, because of the distance you need to cover. In my house I get about 25 Mbit with going one floor up and passing a bathroom. But anyway, this would be the network layout you can build using DD-WRT on you router:

Repeater_Bridge

The funny poles are actually DD-WRT routers and one is configured as the primary. If your modem has wireless and a switch you can just leave that primary router out, since it is just configured as a standard access point. The secondary is actually a DD-WRT router in repeater bridge mode. This means it connects to the access point by wireless and then announces it’s own SSID (e.g. “wifi-study”) whereas the primary announces the “wifi-living”. Now you can use your laptop in the study as well, and connect the PC’s to the router through wired connections. Note that you can replace the antenna with a Yagi antenna and boost the transmission power to get a better reach and a higher wireless speed.

If you run the router in repeater bridge mode, there are a few settings you need to make sure you set correctly:

  1. You must set your encryption to “WPA2 personal” with “AES” encryption.
  2. You must set your wireless channel to a fixed one, so do NOT put it on “auto”.
  3. Please make sure you follow the instructions carefully.

If you do not yet own a DD-WRT capable router you might consider getting one of these new, very fast routers:

  • Netgear WNDR4300
  • Asus RT-AC66U
  • TP-Link TL-WDR4300
  • Cisco Linksys E4200

These very fast routers have awesome specifications and can run DD-WRT perfectly. I have the older, slower Cisco Linksys E2500 and even older and slower Cisco Linksys WRT54GL routers myself, but they also run DD-WRT fine.

Share