Hello world!

Welcome to WordPress. This is your first post. Edit or delete it, then start writing!

Harvested SSH bots passwords


If you have an SSH server running on the public interface, you probably know that there are failed login attempts happening all the time. There are bots scanning whole internet subnets looking for an open TCP port 22 and trying all sorts of popular logins and weak passwords. I wanted to know what passwords and logins are they actually using. There is no problem with logins – audit.log should show them. It’s a different story with passwords. They are not logged even if you configure maxium possible debugging level in OpenSSH server. There is a good reason for doing so – it might violate privacy and pose a security threat.

How did I do that?

The cleanest way to do this is to modify OpenSSH source code. I used OpenSSH 6.4p1 version.

You only need to insert one line using logit function in auth-passwd.c file:

[root@krupa src]# diff -r openssh-6.4p1 openssh-6.4p1_mod
diff -r openssh-6.4p1/auth-passwd.c openssh-6.4p1_mod/auth-passwd.c
> logit("Password, username is: %s-----%s",authctxt->user,password);


 * Tries to authenticate the user using password. Returns true if
 * authentication succeeds.
auth_password(Authctxt *authctxt, const char *password)
 logit("Password, username is: %s-----%s",authctxt->user,password);
 struct passwd * pw = authctxt->pw;
 int result, ok = authctxt->valid;
#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
 static int expire_checked = 0;
 if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES)
 ok = 0;
 if (*password == '\0' && options.permit_empty_passwd == 0)
 return 0;
#ifdef KRB5
 if (options.kerberos_authentication == 1) {
 int ret = auth_krb5_password(authctxt, password);
 if (ret == 1 || ret == 0)
 return ret && ok;
 /* Fall back to ordinary passwd authentication. */
 HANDLE hToken = cygwin_logon_user(pw, password);
 return 0;
 return ok;
#ifdef USE_PAM
 if (options.use_pam)
 return (sshpam_auth_passwd(authctxt, password) && ok);
#if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE)
 if (!expire_checked) {
 expire_checked = 1;
 if (auth_shadow_pwexpired(authctxt))
 authctxt->force_pwchange = 1;
 result = sys_auth_passwd(authctxt, password);
 if (authctxt->force_pwchange)
 return (result && ok);

The results

Over the course of approximately 10 months I was able to gather 1315543 attempts which is about 3 per minute!
There were only 172304 unique combinations.

Top 100 login+password combinations

count login password
 5493 root admin
 2883 root 123456
 2505 root password
 2439 root root
 2423 root root123
 2376 root \001
 2336 root 1234
 2330 root 1qaz2wsx
 2274 root redhat
 2252 root passw0rd
 2217 root 12345678
 2178 root 123123
 2177 root admin123
 2130 root 1q2w3e4r
 2113 root P@ssw0rd
 2097 root qwe123
 2086 root 12345
 1995 root abc123
 1985 root 1234567890
 1958 root 123
 1925 root 1q2w3e
 1877 root 123456789
 1834 root root@123
 1815 root 111111
 1794 root Passw0rd
 1751 root toor
 1748 root 123qwe!@#
 1745 root qweasd
 1743 root 2wsx3edc
 1731 root root1234
 1720 root rootroot
 1711 root master
 1710 root rootme
 1709 root zaq12wsx
 1696 root 123qwe
 1694 root 142536
 1693 root 112233
 1687 root abcd1234
 1660 root 123.com
 1657 root manager
 1656 root 654321
 1641 root data
 1636 root 123abc
 1633 root cisco
 1629 root welcome
 1622 root q1w2e3r4t5
 1612 root 123qweasd
 1601 root qazxsw
 1600 root q1w2e3r4
 1598 root test
 1562 root 1234567
 1560 root 1qaz@WSX
 1557 root qwer1234
 1554 root test123
 1552 root 1q2w3e4r5t
 1539 root oracle
 1539 root 1qazxsw2
 1526 root admin@123
 1505 root qwerty
 1502 root 8812345
 1501 root letmein
 1474 root master123
 1471 root 225588
 1454 root administrator
 1453 root temporal
 1450 root 666666
 1448 root p@ssw0rd
 1447 root 123qwe123
 1441 root 123!@#
 1441 root 11111111
 1426 root 123465
 1424 root changeme
 1422 root 123321
 1418 root r00t
 1411 root 123.321
 1404 root qazwsx
 1404 root monitor
 1392 root default
 1387 root firewall
 1373 root 888888
 1372 root huawei
 1364 root samsung
 1360 root pass123
 1357 root qwe123!@#
 1356 root asdf
 1355 root !QAZ2wsx
 1355 root power
 1355 root 1212
 1354 root pass
 1352 root P@$$w0rd
 1347 root password1
 1345 root Password
 1343 root 65432!
 1341 root P@ssword
 1341 root 88888888
 1340 root Admin@123
 1328 root a123456
 1321 root system
 1313 root Abc123
 1311 root 789789

Top 100 users

count user
1106979 root
 94632 admin
 3140 test
 2917 oracle
 2063 postgres
 2029 nagios
 1793 krupa
 1785 pw
 1685 bin
 1642 user
 1539 guest
 1527 ftpuser
 1296 mysql
 1024 testuser
 950 info
 927 ftp
 820 backup
 815 support
 774 webmaster
 705 git
 605 teamspeak
 560 web
 555 usuario
 548 www
 511 tomcat
 509 postmaster
 502 suporte
 461 teste
 423 deploy
 400 www-data
 380 zabbix
 356 webadmin
 353 ubuntu
 348 test2
 331 svn
 331 alex
 316 apache
 309 test1
 304 ftptest
 291 student
 289 minecraft
 275 ts
 274 jboss
 245 jenkins
 242 master
 228 redmine
 218 test3
 217 ts3
 216 cyrus
 213 jira
 205 testftp
 205 cacti
 203 teamspeak3
 201 nobody
 199 user1
 188 hadoop
 181 webuser
 175 news
 174 adm
 170 a
 168 sales
 162 db2inst1
 159 prueba
 159 john
 157 testing
 156 office
 156 mythtv
 150 temp
 148 demo
 145 weblogic
 141 tom
 141 david
 139 cron
 138 tester
 137 mail
 132 vyatta
 131 postfix
 129 gitosis
 124 service
 121 bash
 118 server
 115 michael
 114 gitolite
 113 linux
 113 daemon
 113 ben
 110 ivan
 109 operator
 108 public
 108 mike
 108 jack
 106 http
 105 upload
 105 rsync
 105 daniel
 105 anna
 104 informix
 104 ghost
 102 pi
 102 deployer

There are quite a lot of attempts using my domain name which means those bots have some adaptation abilities.


Top 100 passwords

count password
 9747 123456
 6759 admin
 5863 password
 4362 1234
 3826 12345
 3530 123
 3490 root
 3475 1qaz2wsx
 3414 test
 3339 123123
 3259 abc123
 3258 root123
 3121 12345678
 3085 qwe123
 3073 admin123
 3069 passw0rd
 3053 P@ssw0rd
 3037 redhat
 3007 1q2w3e4r
 2745 1234567890
 2617 test123
 2610 Passw0rd
 2609 111111
 2604 zaq12wsx
 2587 123qwe
 2580 root@123
 2520 qweasd
 2494 112233
 2484 oracle
 2464 2wsx3edc
 2428 master
 2424 142536
 2422 toor
 2420 123qwe!@#
 2410 rootme
 2376 123456789
 2376 \001
 2366 data
 2338 manager
 2332 qwerty
 2323 root1234
 2316 welcome
 2293 rootroot
 2288 cisco
 2281 qazxsw
 2275 q1w2e3r4t5
 2258 123.com
 2216 1q2w3e
 2216 123abc
 2195 123qweasd
 2163 abcd1234
 2152 1234567
 2133 letmein
 2115 8812345
 2103 1qazxsw2
 2089 123!@#
 2085 225588
 2082 123465
 2078 master123
 2073 q1w2e3r4
 2073 admin@123
 2065 qwer1234
 2053 temporal
 2050 123.321
 2044 123qwe123
 2029 1qaz@WSX
 2025 654321
 2008 changeme
 1988 pass
 1979 monitor
 1966 666666
 1934 1212
 1929 1
 1919 firewall
 1887 qwe123!@#
 1874 r00t
 1871 qazwsx
 1869 1q2w3e4r5t
 1851 65432!
 1840 p@ssw0rd
 1834 administrator
 1831 default
 1827 Admin@123
 1825 pass123
 1810 P@$$w0rd
 1803 789789
 1793 Abc123
 1776 123321
 1772 root123!@#
 1765 aa123456
 1765 147147
 1763 11111111
 1754 password1
 1752 q123456
 1723 tang
 1717 admin123#
 1717 888888
 1715 huawei
 1709 system
 1701 adminadmin



Is it a problem? It should not be unless you use one of those passwords. It only creates unnecessary noise in the log files.

If you are concerned about someone guessing your password you can change the port SSH listens on, but there are good reasons not to. I would recommend reading that article even though the author goes to the extreme saying it is absolutely a bad idea. Moving SSH port to some unpredictable value will not protect you from targeted attack but will allow you to buy more time to patch your system in case there is 0day attack on the OpenSSH server and the bots will rush to compromise as many systems as possible as fast as possible – they will scan port 22 only to speed up the process.

Securing your router with iptables firewall


Iptables is a linux firewall built into the linux kernel. It is a proven solution that has been around for quite some time (since kernel 2.4). It is used for filtering, NAT and packet mangling. We will not be going through all of the iptables features here. We will focus on the basic features that will help us secure our home router. The assumption here is that you have a router with two interfaces (or subinterfaces): one connecting it to LAN (eth0.1 in our case) and one connecting it to the internet (eth0.2 in our case). You should be familiar with it if you read my previous tutorial.

Do I need this?

It all depends on what you are trying to protect and how your network environment looks like. If you only want to copy the behaviour of the regular home router then you only need NAT rule. It will protect you against any connections initiated from the internet. There are exceptions to this rule: 1. You explicitly specify that a port is forwarded to the internal host. 2. Router and user applications support UPnP protocol (I believe it was enabled by default on my TP-LINK router). With the help of this protocol application can inform router that it needs to forward specific port to it. It happens automatically and without knowledge of the user (of course you can check the status of open ports manually in the web interface of the router). There is an implementation of upnp on linux but we will not be covering it. I am not using it and haven’t noticed any problems so far.


There are 4 tables:

  • filter – used for packet filtering
  • nat – used for address translation
  • mangle – used for packet modification
  • raw – preprocessing, packets go to this table first

I will only cover filter an nat tables (limited).

Traffic filtering

To disply contents of specific table you can issue command:

iptables -L -t table_name

To see more details (like input and output interface) you can add -v flag. Filter table is the default table. Let’s see the default contents of filter table:

root@raspberrypi:~# iptables -L -v
Chain INPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination

Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination

You can see that there are three so-called “chains”: INPUT, OUTPUT and FORWARD. INPUT chain filters packets that are destined to the machine itself (for example someone is trying to connect to server listening on the linux box or there are returning packets for application that initiated connection on this box). In other words it filters packets destined for local process. OUTPUT chain filters packets that originate from that box. FORWARD chain filters packets that are routed through the box. The linux box is not source nor destination of the packet.

Methods of applying rules

You can add rule immediately using iptables command. Please note that you need root privileges to modify iptables rules.

iptables -A INPUT -i eth0.2 -j DROP

It will cause all packets which are destined for local system and are incoming on the eth0.2 interface to be dropped. It will be applied immediately. However, it won’t persist through the reboot. You need to save them to a file first.

iptables-save > /etc/iptables

If you display contents of the /etc/iptables file you will see the skeleton of a valid configuration file that you can edit manually and apply to the running configuration.

# Generated by iptables-save v1.4.14 on Sun Dec 1 22:59:53 2013
# Completed on Sun Dec 1 22:59:53 2013
# Generated by iptables-save v1.4.14 on Sun Dec 1 22:59:53 2013
:FORWARD ACCEPT [135:11104]
:OUTPUT ACCEPT [377:48999]
# Completed on Sun Dec 1 22:59:53 2013
# Generated by iptables-save v1.4.14 on Sun Dec 1 22:59:53 2013
:OUTPUT ACCEPT [377:48999]
# Completed on Sun Dec 1 22:59:53 2013
# Generated by iptables-save v1.4.14 on Sun Dec 1 22:59:53 2013
:INPUT ACCEPT [503:43636]
:FORWARD ACCEPT [135:11104]
:OUTPUT ACCEPT [377:48999]
# Completed on Sun Dec 1 22:59:53 2013

I will come back and explain the file syntax later.

To restore the rules from the file (apply them to the running configuration) use:
iptables-restore < /etc/iptables

How do rules in a chain work

Chain in a table is a list of rules. When a packet arrives the rules are examined from top to bottom. If the criteria match, the action is taken. The packet is processed until it is dropped, rejected or accepted. If it is accepted then it moves to another table. For example, when packet is routed through my home router with NAT enabled, the packet goes through filter table, nat table, raw table and mangle table. In this case raw and mangle table will not do anything to the packet (they have default policy ACCEPT on all their chains). If you want to learn more here is a good tutorial on iptables.


ACCEPT – Packet is accepted

DROP – Packet is silently dropped

REJECT – Packet is dropped but the sender is notified by packet with RST flag sent (if it was TCP packet) or ICMP port unreachable (udp).

So should we use drop or reject?

I prefer to use REJECT in a trusted environment. It makes troubleshooting network problems easier.

In the untrusted networks I prefer to drop packets. If you reject them actively then someone can flood your host with packets destined for closed port and saturate not only your downstream bandwidth but also upstream bandwidth by forcing you to reply to those packets (or even use you in the DDoS attack).

Default policy

The default policy is the action that is taken when no rules in a chain match the packet or if the rules that match don’t apply DROP, REJECT or ACCEPT policy. You can configure it using -P flag:

iptables -t table_name -P chain_name action

for example (filter is the default table)


Text file syntax

In the abovementioned text file the tables are marked with asterisk.  After semicolon there is chain name along with the default policy. In the brackets there are number of packets and bytes that matched the policy (they are there so that you don’t lose your counters state after the reboot or configuration changes). Below them you can enter the rules you want applied to the chain. You enter them in the same way as you do in command line but without ‘iptables’ at the front. At the end of table configuration there is COMMIT keyword. See the examples below.

Clearing rules

In order to clear all rules in a table use

iptables -t table_name -F

Please note it does not reset default policy of the chains to ACCEPT!


This is bare minimum (remember to enable ip forwarding!) I already discussed in the previous post .

iptables -t nat -A POSTROUTING -o eth0.2 -j MASQUERADE

Where eth0.2 is the interface facing the internet. If you want to write it directly to the configuration file you can do this in this manner:


Remember you can always generate the config file using iptables-save command.

If you want to forward specifc port on your local machine use (in this case there is a web server on the internal address that I want accessible from the internet):

iptables -t nat -A PREROUTING -i eth0.2 -p tcp --dport 80 -j DNAT --to-destination

or in the config file:

-A PREROUTING -i eth0.2 -p tcp --dport 80 -j DNAT --to-destination

 Filtering traffic

Instead of specifying ACCEPT, DROP or REJECT actions you can redirect the packet to be processed by your custom chain. If your custom chain doesn’t perform any of these actions on the packet, then the packet returns to the chain it was before in.

Create custom chain by:

iptables -t table -N my_custom_chain

Stateful firewall

Iptables supports stateful firewall. What it means is that it remembers that a connection has been made and allows returning traffic. By using this you can allow connections to be initiated from one zone of your firewall to the other, but not the other way around. It is similar to the NAT: clients from LAN can easily initiate connections to the outside world, but hosts in the internet can not initiate connections to the clients in LAN unless you forward a port. There are 5 connection states in iptables:

  • NEW – the packet initiates new connection
  • ESTABLISHED – packet is a part of already established connection
  • RELATED – some protocols, like FTP open secondary connections using data exchanged in the original connection. Iptables can detect it (for chosen protocols, like FTP) and allow such traffic
  • INVALID – packet can’t be identified or doesn’t have state
  • UNTRACKED – you can mark the connection as untracked in the raw table

Let’s see the example:

#default policies
:INPUT DROP [9:501]
:FORWARD DROP [135:11104]
:OUTPUT ACCEPT [377:48999]

#custom chains created
:lan_bad_conn - [0:0]
:wan_incoming - [0:0]

#allow loopback traffic so that local applications can communicate by TCP/IP protocol
-A INPUT -i lo -j ACCEPT
#allow ssh and icmp to our router 
-A INPUT -i eth0.1 -p tcp -s --dport 22 -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i eth0.1 -p icmp -j ACCEPT
#For DHCP info check the end of the post!

#let's filter and log bad traffic incoming from WAN
-A INPUT -i eth0.2 -j wan_incoming

#and from LAN
-A INPUT -i eth0.1 -j lan_bad_conn

#don't forget to allow traffic to your internal server that you forwarded ports to
#-A FORWARD -i eth0.2 -p tcp --dport 80 -j ACCEPT

#allow initiating connections from LAN to the internet. Don't forward packets with source ip addresses that shouldn't be there. These forward rules are actually obsolete when you're behind NAT.
-A FORWARD -i eth0.1 -s -m state --state NEW,RELATED,ESTABLISHED -j ACCEPT
#allow returning traffic
-A FORWARD -i eth0.2 -m state --state RELATED,ESTABLISHED -j ACCEPT
#filter and log bad traffic
-A FORWARD -j lan_bad_conn

# filter and log packets with source address that is not expected on our LAN. Limit filtering to 1 message per minute with 5 messages burst. Add prefix "lan_bad_conn: " to logged messages. Messages will be logged to /var/log/messages by default but that depends on the configuration of your syslog daemon. '!' means negation.
-A lan_bad_conn ! -s -m limit --limit 1/min --limit-burst 5 -j LOG --log-prefix "lan_bad_conn: "
# filter and log bad traffic
-A lan_bad_conn -m state --state INVALID,UNTRACKED -m limit --limit 1/min --limit-burst 5 -j LOG --log-prefix "lan_bad_conn: "
# drop those packets 
-A lan_bad_conn -j DROP

#Allow only returning traffic from connections established by the router itself. Log and drop the rest
-A wan_incoming -m state --state RELATED,ESTABLISHED -j ACCEPT
-A wan_incoming -m state --state INVALID,NEW,UNTRACKED -m limit --limit 1/min --limit-burst 5 -j LOG --log-prefix "wan_bad_incoming: "
-A wan_incoming -m state --state INVALID,NEW,UNTRACKED -j DROP


Viewing connections

You can view the current connections tracked by iptables by viewing file /proc/net/ip_conntrack

Do iptables always work?

No. Try to block DHCP requests using iptables. It won’t work. That’s why I didn’t include the rule allowing my clients to obtain ip address from DHCP server. Iptables only work with standard TCP/IP stack. However application can open raw socket which allows it bypass TCP/IP stack and create custom packets, including custom protocols. The DHCP discover packets will eventually be blocked by iptables, but they will be seen by the application first. Is it a security threat? Not so much, because you need root privileges to open raw socket. If malicious application has root privileges then your server is already fully compromised because the application will have access to everything (for example it could modify iptables rules).There is an interesting discussion on this mailing list: https://www.mail-archive.com/netfilter@lists.samba.org/msg03905.html .


These are the basics of iptables that come to my mind. I plan to explain some additional, more advanced features of iptables in the future.

Raspberry pi as a home router part 2: Basic routing


In the previous article we turned TP-LINK router into VLAN-enhanced switch to support our “router on a stick” configuration. In this article we will configure basic routing and services needed to get working internet connection for your LAN devices. In this tutorial we will be using Raspberry PI version B (the one with fast ethernet port) and Raspbian linux – one of the most popular RPI linux distributions based on Debian.

Configuring VLAN interfaces

First we need to install proper kernel modules that add VLAN functionality. We will be issuing all commands as root.

apt-get install vlan

We need to make sure that the modules are loaded on system startup.

echo 8021q >> /etc/modules

Reboot your raspberry pi. If you don’t want to reboot it you can load it manually by typing:

modprobe 8021q

Next, it’s time to create VLAN subinterfaces. We could accomplish that by using vconfig utility but we want our configuration to persist through reboot so we will be editing proper configuration files. Interface eth0 will capture and transmit untagged frames. On the other hand interfaces eth0.N will work with tagged frames belonging to VLAN number N. Since we have chosen to tag both VLAN 1 and VLAN 2 on the trunk link in the previous part of the tutorial , we will create proper configuration for this scenario. I’ll just paste my configuration file. The file responsible for basic network configuration in Debian-like systems is /etc/network/interfaces:

auto lo eth0.1 eth0.2
allow-hotplug eth0
iface lo inet loopback

iface eth0.1 inet static
iface eth0.2 inet dhcp

The first line is very important. According to the debian documentation auto keyword means that the interface will start with the system. In my understanding if you skipped this you would have to start the interface manually each time using ifconfig eth0.1 up command. This is not the case. If you don’t include this line the interface will not even be created at startup so it is mandatory. allow-hotplug should bring the interface up when cable is plugged in if I understand it correctly but it’s still not working for me. This is minor flaw and I will think about fixing it later. You can reboot and check if the settings are applied.

WAN side

You should get your ip address from ISP automatically with the above settings. You can also configure it statically if your ISP gave you static IP address.

DNS servers addresses will be save automatically to the /etc/resolv.conf file.

LAN side – DHCP server

Devices in your LAN will be getting addresses from the DHCP server on your router. This is not mandatory – you can configure all of them statically, however I recommend setting up DHCP server because it is very easy. First install it:

apt-get install isc-dhcp-server

I also recommend installing a tool that will help you to easily manage which daemons will be started automatically at boot time:

apt-get install chkconfig

DHCP server configuration file is in /etc/dhcp/dhcpd.conf. You just have to add additional section at the bottom specifying the settings for your LAN subnet:

subnet netmask {
option routers;
default-lease-time 86400;
max-lease-time 604800;
option domain-name-servers,;

range value defines addresses range that can be assigned dynamically

routers value is the default gateway

default-lease-time and max-lease-time – when a client requests the ip address, it is given to it only for a limited amount of time called the lease time. Default-lease-time is given when the client doesn’t ask for specific lease time. Max-lease-time is a maximum client can get.

domain-name-servers are addresses of DNS servers

You can add reservation for a client. This way that client will always get the same IP address from DHCP. The clients are recognized based on MAC address. Example:

host my_pc { hardware ethernet 01:23:45:67:89:ab ; fixed-address;}

Host name (my_pc in this case) is arbitrary and doesn’t have to correspond to any real value. Reservations should be configured outside of range of dynamically assigned addresses. If for some reason you need it to be in the middle of dynamic range you can split the range. For example, if you wanted to assign reservation for address inside range, you can split the range in two:


In order to apply configuration changes you need to restart the DHCP server:

service isc-dhcp-server restart

To make sure that it is always started after reboot enter:

chkconfig isc-dhcp-server on


You don’t need to worry about basic routing. Routes for directly connected networks are automatically added to the routing table. Default gateway is automatically added to routing table by DHCP client based on the information from your ISP. You can display your routing table by issuing command:


You only need to enable routing because by default it is disabled. To enable it immediately (it will not persist after reboot):

echo 1 > /proc/sys/net/ipv4/ip_forward

To enable it permanently (reboot required) add or change or uncomment the following line in /etc/sysctl.conf:


Network Address Translation

You need NAT so that multiple machines behind your router can use a single global IP address that ISP gives you. To enable NAT enter:

iptables -t nat -A POSTROUTING -o eth0.2 -j MASQUERADE

If you want to forward a port (for example port 80 on internal address) to the server inside your LAN enter:

iptables -t nat -A PREROUTING -i eth0.2 -p tcp --dport 80 -j DNAT --to-destination

The changes will not persist through reboot. First, save the rules to the file:

iptables-save > /etc/iptables

Then you need to make sure those rules are applied when the system starts. A good place for that is to create a script inside /etc/network/if-pre-up.d directory. All scripts inside that directory are executed when the interface is brought up.

vi /etc/network/if-pre-up.d/iptables

Paste the following content:


iptables-restore < /etc/iptables

exit 0

Then make sure it is executable:

chmod +x /etc/network/if-pre-up.d/iptables

You can display the contents of your iptables NAT table by typing:

iptables -L -t nat

Iptables is quite powerful linux firewall and it has much more features. I will make an article about them sometime later.


This should get your Raspberry Pi router up and running really fast but with basic functionalities (similar to the features of cheap 20$ routers). I will be covering more advanced topis later. It is very possible that I forgot something or I made a mistake. If so, please let me know down below in comments section.