Your MikroTik router have 3 main chains for rules: Input, Output and Forward.
Packets with a destination ip on the router (see /ip addresses for a list) will be checked with the input chain, so for the router itself or if you have local devices where public IPs are port forwarded to a NATed IP, you need to use the input chain.
The output chain is for packets with a source IP on the router, meaning all packets originating on the router will be checked with the output chain. If you are using the router as DNS server for your local network, it's DNS requests will be using the output chain.
The forward chain is for all packets going through the router - being forwarded to a public IP either inside or outside of the router. In a server environment, the forward chain is therefore what you use the most. In a very basic server environment, on the forward chain you will want to accept ports like 80+443 (web) for everyone, accept 22+3389 (ssh/rdp) for yourself, and drop the rest of the packets.
A MikroTik router processes rules from the top to the bottom and stops processing more rules, whenever it finds a rule that is true for the packet. If it doesn't meet any rules that are true, the packet is accepted, you should therefore end the list with a drop rule with in-interface set to your internet interface. If you forget the in-interface, the drop rule will affect all packets going both in and out, and probably stop a lot of things on your clients from working, as you primarily want only to drop traffic from the outside getting in.
You will primarily be using two actions. You either accept the packets or you drop the packets. Accept will stop processing any more rules and let the packet through. Drop will also stop processing any more rules, and delete (drop) the packet without letting the sender know that the packet is dropped. You can also reject the packet, that is delete the packet and tell the sender that you deleted it, but by doing that you are really aiding any malicious sender, by letting them know that there is a device here. So it is generally not recommended to reject, just drop it.
In your firewall - especially on a core device like your router - you need to minimize the amount of checks, as each check requires precious CPU power. Routers therefore use connection tracking, to check the connection state. For all new connections, we need to check all our rules, to see if we want the connection to go through. But for all subsequent packets in the same connection, we don't need to check them as the connection have already been checked, so for all connections already established (or related, that is ex. an FTP connection opening another data port), we want to accept all the packets.
Therefore it is usually wise to begin your firewall rules with an input/forward accept rule for all connection-state=established/related. As a MikroTik stops processing rules further down the list, whenever a rule is found to be true, you can bypass all subsequent rules and minimize CPU usage for all established/related packets, by putting this rule at the top of your firewall list.
If your router is protecting servers, the established/related rule should be chain=forward. If it is in front of your office or home, it should be chain=input. If there are both clients with local IPs and servers with public IPs behind your router, you need two rules, one with both chains.
For your servers inside your network, you will usually be accepting connections depending on their destination addresses, destination ports or combinations. Or you can use destination address lists, to check for a list of different IPs created in /ip firewall address-list.
To reduce the rules checked per connection, you can save a lot of checks by jumping to different chains. That means Goto, if you ever programmed Basic. If you need to accept different protocols for a specific server, all connections will have to be checked with each rule. But if you instead start by jumping to your own chain, depending on the server IP, you have reduced the check to only one check for all other connections, besides those to the specific server.
If you type your own chain name (instead of input/output/forward) when you create a new filter rule, a new chain will be created. For the next filter rule you create, you will see this new chain available in the chain list.
Firewall rules quickly become complex and you will find it hard to remember their reason. In Winbox use the shortcut Ctrl+M to add comments to every rule you create, so that later, you will be able to remember, why this specific rule exists.
If you find parts of your firewall hard to understand, you can add extra accept/drop rules to see if they catch the traffic. Any filter rule you add, will provide a counter showing all traffic they have matched, so adding extra temporary rules, may help you debug and understand your firewall.
For even higher speed, you can let packets skip parts of the routers internal systems. You do this by adding fasttrack filter rules and mangle rules. It may produce the speed you need, but remember that to obtain the speed it also means that these packets are skipping parts of the router that are often essential (like the firewall), so use fasttrack with caution. Read more about Fasttrack.
The two major protocols used are UDP and TCP.
An UDP packet just get sent, and there is no response - therefore there is no connection for UDP, it's just a packet that may or may not be received by the destination, the sender won't know.
TCP works by opening connections. Often you use a hostname, like tikdis.com, so first a DNS server is checked to get the IP. With the IP, the TCP/IP connection can be opened.
First the sender starts the 3-way handshake, by sending a A SYN (synchronize) packet. Then the tikdis.com server responds with a SYN-ACK (synchronize acknowledgement) packet to acknowledge the SYN packet is received. And finally the sender sends ACK to the server, to acknowledge that a connection is established. Until the connection is established, the router regards the connection as new, so 3 packets are needed to establish a connection. If a user watches a movie at a size of 2 GiB, the server needs to send roughly 1,5 million packets to deliver the full movie. So using established rules, you can save extreme amounts of the routers processing power. Or by creating firewalls without proper established rules, you can quickly overload any router.
Ending a connection properly, means executing a 4-way handshake using FIN and ACK. A MikroTik router will close (tcp-close-wait-timeout) a connection, if there is no response for 10 seconds. This is much faster than the Linux default which is 60 seconds - there is a comparison here.
A MikroTik router considers a connection invalid, if it have not received the proper 3-way handshake. So in most situations, you can and should drop invalid connections, as they are probably an attempt to break into your network. There are however a few situations, where invalid connections are in fact valid.
If you are using BGP or OSPF, you might have internet traffic incoming at one router, and going out on another router if BGP have concluded that this is the shortest path. This will mean that part of the 3-way handshake is on one router, and the other part is on the other router. This is fine and fully acceptable, but this also means that both MikroTik routers will put the connection in connection-state=invalid. Dropping invalid packets in this situation, will create strange scenarios, that will be very hard to debug. So be careful dropping invalid packets, if you are using BGP or OSPF.
Most admins know, that you should only open ports you need, and drop all other packets. But often there are web applications that you have to leave open to the public, even though you would prefer to lock them down by IP/VPN. In a hosting environment it might be phpMyAdmin and WordPress.
Setting up brute-force prevention on your router, will immensely increase your security. And it may reduce huge amounts of traffic, that may be eating up CPU on you web/database servers, when brute-force attempts are running. Here are some examples of banning a user trying to brute force the router:
In this example we inspect the content in the package, looking for the the text 530 Login incorrect, that we know our FTP server responds, if the login fails. This requires that the connection is not encrypted, and that we know the response of our server.
1 2 3 4 5 6 7 8 | /ip firewall filter add chain=input protocol=tcp dst-port=21 src-address-list=ftp_blacklist action=drop \ comment="drop ftp brute forcers" add chain=output action=accept protocol=tcp content="530 Login incorrect" dst-limit=1/1m,9,dst-address/1m add chain=output action=add-dst-to-address-list protocol=tcp content="530 Login incorrect" \ address-list=ftp_blacklist address-list-timeout=3h |
This example protects the ssh service on the router. It works by adding the ip to a list, if a connection is not established, because if the packet going through failed to establish a connection, the login attempt must have failed. It is repeated 3 times adding the IP to a new list, to set ban the IP after 3 login attempts.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | /ip firewall filter # If IP is in address list ssh_blacklist then drop the packet add chain=input protocol=tcp dst-port=22 src-address-list=ssh_blacklist action=drop \ comment="drop ssh brute forcers" disabled=no # If IP is ssh_stage3 and state is new, then add IP to address list: ssh_blacklist add chain=input protocol=tcp dst-port=22 connection-state=new \ src-address-list=ssh_stage3 action=add-src-to-address-list address-list=ssh_blacklist \ address-list-timeout=1d comment="" disabled=no # If IP is ssh_stage2 and state is new, then add IP to address list: ssh_stage3 add chain=input protocol=tcp dst-port=22 connection-state=new \ src-address-list=ssh_stage2 action=add-src-to-address-list address-list=ssh_stage3 \ address-list-timeout=1m comment="" disabled=no # If IP is ssh_stage1 and state is new, then add IP to address list: ssh_stage2 add chain=input protocol=tcp dst-port=22 connection-state=new src-address-list=ssh_stage1 \ action=add-src-to-address-list address-list=ssh_stage2 address-list-timeout=1m comment="" disabled=no # Add IP to address list: ssh_stage1 add chain=input protocol=tcp dst-port=22 connection-state=new action=add-src-to-address-list \ address-list=ssh_stage1 address-list-timeout=1m comment="" disabled=no # Also ban the IP for SSH on all our servers behind the router (chain=forward) add chain=forward protocol=tcp dst-port=22 src-address-list=ssh_blacklist action=drop \ comment="drop ssh brute downstream" disabled=no |
This is the same as the example above, but we are now checking SSH and RDP (Microsoft remote/terminal service) for brute force attempts for servers inside our network. You can add extra ports, to brute-force protect more services in your network.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | /ip firewall filter # Always allow your local IPs access (do not ban yourself) add chain=forward dst-port=22,3389 src-address=192.168.0.0/24 action=accept add chain=forward protocol=tcp dst-port=22,3389 src-address-list=ssh_blacklist action=drop \ comment="drop ssh brute forcers" disabled=no add chain=forward protocol=tcp dst-port=22,3389 connection-state=new \ src-address-list=brute_stage3 action=add-src-to-address-list address-list=ssh_blacklist \ address-list-timeout=1d comment="" disabled=no add chain=forward protocol=tcp dst-port=22,3389 connection-state=new \ src-address-list=brute_stage2 action=add-src-to-address-list address-list=brute_stage3 \ address-list-timeout=1m comment="" disabled=no add chain=forward protocol=tcp dst-port=22,3389 connection-state=new src-address-list=brute_stage1 \ action=add-src-to-address-list address-list=brute_stage2 address-list-timeout=1m comment="" disabled=no add chain=forward protocol=tcp dst-port=22,3389 connection-state=new action=add-src-to-address-list \ address-list=brute_stage1 address-list-timeout=1m comment="" disabled=no |
A MikroTik RouterOS unit can be used as a firewall appliance, both as a virtual CHR firewall appliance or a hardware appliance.
Use bogon script, to protect you against: SynFlood, ICMP Flood, Port Scan, e-mail spam.
1 2 3 | # Create Regexp for layer 7 filtering /ip firewall layer7-protocol add name=youtube regexp="^.*(host|HOST).+(youtube).*\\\$" |
1 2 3 4 5 6 7 8 9 | # Mark the connection and packets /ip firewall mangle add action=mark-connection chain=prerouting protocol=udp dst-port=53 \ connection-mark=no-mark layer7-protocol=youtube \ new-connection-mark=youtube_conn \ comment=youtube passthrough=yes add action=mark_packet chain=prerouting connection-mark=youtube_conn \ new-packet-mark=youtube_packet |
1 2 3 4 | # Drop the packets if they are marked /ip firewall filter add action=drop chain=forward packet-mark=youtube_packet add action=drop chain=input packet-mark=youtube_packet |
1 2 3 4 5 6 7 8 9 | # Remember that layer 7 only blocks unencrypted http traffic! /ip firewall layer7-protocol # Blocking /admin/ add name="http admin1" regexp="^GET\\ /admin/" # Blocking /admin/ based on the protocol add name="http admin2" regexp="^GET\\ /admin/[^\\ ]*\\ HTTP/1\\.(0|1)" /ip firewall filter add action=reject chain=forward dst-port=80 layer7-protocol="http admin1" protocol=tcp reject-with=tcp-reset |
Another way:
/ip firewall mangle add action=mark-packet chain=prerouting comment=youtube disabled=no \ in-interface=eth1 layer7-protocol=youtube new-packet-mark=youtube \ passthrough=yes