Welcome to WordPress. This is your first post. Edit or delete it, then start writing!
Harvested SSH bots passwords
Introduction
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 82a83 > logit("Password, username is: %s-----%s",authctxt->user,password);
/* * Tries to authenticate the user using password. Returns true if * authentication succeeds. */ int 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; #endif #ifndef HAVE_CYGWIN if (pw->pw_uid == 0 && options.permit_root_login != PERMIT_YES) ok = 0; #endif 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. */ } #endif #ifdef HAVE_CYGWIN { HANDLE hToken = cygwin_logon_user(pw, password); if (hToken == INVALID_HANDLE_VALUE) return 0; cygwin_set_impersonation_token(hToken); return ok; } #endif #ifdef USE_PAM if (options.use_pam) return (sshpam_auth_passwd(authctxt, password) && ok); #endif #if defined(USE_SHADOW) && defined(HAS_SHADOW_EXPIRE) if (!expire_checked) { expire_checked = 1; if (auth_shadow_pwexpired(authctxt)) authctxt->force_pwchange = 1; } #endif result = sys_auth_passwd(authctxt, password); if (authctxt->force_pwchange) disable_forwarding(); 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
Conlusion
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
Introduction
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.
Tables
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 *nat :PREROUTING ACCEPT [10:674] :INPUT ACCEPT [9:561] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] COMMIT # Completed on Sun Dec 1 22:59:53 2013 # Generated by iptables-save v1.4.14 on Sun Dec 1 22:59:53 2013 *filter :INPUT ACCEPT [9:501] :FORWARD ACCEPT [135:11104] :OUTPUT ACCEPT [377:48999] COMMIT # Completed on Sun Dec 1 22:59:53 2013 # Generated by iptables-save v1.4.14 on Sun Dec 1 22:59:53 2013 *raw :PREROUTING ACCEPT [640:55452] :OUTPUT ACCEPT [377:48999] COMMIT # Completed on Sun Dec 1 22:59:53 2013 # Generated by iptables-save v1.4.14 on Sun Dec 1 22:59:53 2013 *mangle :PREROUTING ACCEPT [640:55452] :INPUT ACCEPT [503:43636] :FORWARD ACCEPT [135:11104] :OUTPUT ACCEPT [377:48999] :POSTROUTING ACCEPT [512:60103] COMMIT # 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.
Actions
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)
iptable -P OUTPUT ACCEPT
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!
NAT
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:
... *nat :PREROUTING ACCEPT [10:674] :INPUT ACCEPT [9:561] :OUTPUT ACCEPT [0:0] :POSTROUTING ACCEPT [0:0] -A POSTROUTING -o eth0.2 -j MASQUERADE COMMIT ...
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 192.168.33.10 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 192.168.33.10:80
or in the config file:
-A PREROUTING -i eth0.2 -p tcp --dport 80 -j DNAT --to-destination 192.168.33.10:80
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:
*filter #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 192.168.33.0/24 --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 192.168.33.0/24 -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 192.168.33.0/24 -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 #commit COMMIT
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 .
Conclusion
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
Introduction
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 address 192.168.33.1 netmask 255.255.255.0 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 192.168.33.0 netmask 255.255.255.0 { range 192.168.33.100 192.168.33.200; option routers 192.168.33.1; default-lease-time 86400; max-lease-time 604800; option domain-name-servers 8.8.8.8, 8.8.4.4; }
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 192.168.33.20;}
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 192.168.33.150 inside range 192.168.33.100-200, you can split the range in two:
range 192.168.33.100 192.168.33.149; range 192.168.33.151 192.168.33.200;
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
Routing
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:
route
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:
net.ipv4.ip_forward=1
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 192.168.33.138 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 192.168.33.138:80
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:
#!/bin/bash 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.
Summary
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.