[HowTo] Basic DOS protection in FreeBSD

09/02/2013 04:25 .Shōgun#1
Hello everyone,

Today I want to share with you some useful tips to protect your server from Denial of Service attacks. This tutorial assumes that you are running Metin2 server under FreeBSD 9.x (might work on earlier versions too) on a dedicated server. I only worked with dedicated servers so I can't help you much with Hamachi or local servers.

Enabling the pf firewall

Add the following line to /etc/rc.conf

Code:
pf_enable="YES"
Next we need to configure the firewall before we start it to avoid locking out ourselves, so we run the command:

Code:
ee /etc/pf.conf
Configuring pf

The "code" lines in this section are intended to be entered in /etc/pf.conf. This file may exist or not in your system, if it's already present, just delete everything on it and add the following lines, making the necessary changes for your setup as shown under each part of the file.

Code:
ext_if="em0"
Replace em0 with your external interface name. You can find out its name by typing the ifconfig command in the shell. Example here:

[Only registered and activated users can see links. Click Here To Register...]

Code:
service_ports="{ 22 }"
game_ports="{ 11000, 13000, 13010, 13020, 13030, 13099 }"
Here you should enter the ports which should be open to the public. In this example, we enter the standard ssh port 22 and the metin2 game ports (auth and a port for every core except db which doesn't need to be open to outside access). If you are running your website on the same machine, you should open port 80 as well. If you have a separate webserver which connects to this machine for database queries, do not open port 3306 here; instead ad the IP of this webserver in the next part.

Code:
table <trusted_hosts> const { 8.8.8.8, 8.8.8.4 }
table <abusive_hosts> persist
Replace those IP addresses with the IP addresses that you want to skip firewall rules and have unlimited access to all ports. I suggest entering your website IP here (if it's on a different machine) and your own IP (to avoid locking yourself out by a mistake the first time you enable pf)

If your own IP gets blocked out you can always use SSH from your other server(s) to unblock it (more on this later), or the rescue mode provided by some hosting companies.

Code:
# options
set block-policy drop
set loginterface $ext_if
set skip on lo

scrub on $ext_if reassemble tcp no-df random-id

antispoof quick for { lo0 $ext_if }
Rules for packet normalization, anti spoof and other complicated stuff. No need to edit this part (if you are really interested on what this does, google for pf.conf)

Code:
block in

pass out all keep state
pass out on $ext_if all modulate state

pass in quick from <trusted_hosts>
block in quick from <abusive_hosts>

pass in inet proto icmp all icmp-type echoreq

pass in on $ext_if proto tcp to any port $service_ports flags S/SA keep state \
        (max-src-conn 40, max-src-conn-rate 20/5, overload <abusive_hosts> flush)

pass in on $ext_if proto {tcp,udp} to any port $game_ports flags S/SA keep state \
        (max-src-conn 40, max-src-conn-rate 20/5, overload <abusive_hosts> flush)
These are the firewall rules and normally you don't need to edit this. The key part is the rate limiting which blocks IP addresses that make an excessive number of connections to your machine. In this case I have set some quite strict limits. We leave UDP open since the original client uses UDP to check on the channel state, if your client doesn't need this it's a good idea to block udp completely. In this case we would replace the "proto {tcp,udp}" part with "proto tcp".

This is all for pf.conf, you can find the whole text file here:

[Only registered and activated users can see links. Click Here To Register...]

If you are using official login code and need UDP use this instead:

[Only registered and activated users can see links. Click Here To Register...]

Troubleshooting

A legitimate player could get blocked if he logs in a lot of accounts, or you can get blocked yourself out of the system if you make many connections for whatever reason. In this case run this command to remove the IP from the abusive_hosts table:

Code:
pfctl -t abusive_hosts -T delete 8.8.8.8
Where 8.8.8.8 is the Ip address you want to unblock. If you want to do the opposite (block an IP manually) the command you need is:

Code:
pfctl -t abusive_hosts -T add 8.8.8.8
Starting pf & final words

Finally, once you are happy with the setup, you can enable the firewall with the following command:

Code:
service pf start
If this command fails (pf is not loaded), use this command to load it first:

Code:
kldload pf.ko
And that's it. Please note that this won't make you inmune to any DoS attack, but will help you with most of the weak ones. If people show interest, I will write more tutorials on how to protect your website, etc.

Safe settings on sysctl

Disclaimer: I'm by no means a FreeBSD expert, I collected this stuff from some sources and put it together, and so far it's working for me.

Just copy and paste this on your /etc/sysctl.conf, unless you have some custom stuff in there already.

These system settings limit the chances of some attacks to succeed.

Code:
security.bsd.see_other_uids=0

tcp.path_mtu_discovery=0

sysctl net.inet.tcp.syncookies=1
net.inet.ip.forwarding=1
net.inet.ip.fastforwarding=1
net.inet.tcp.nolocaltimewait=1
net.inet.tcp.syncache.rexmtlimit=1
net.inet.ip.check_interface=1         
net.inet.ip.portrange.randomized=1   
net.inet.ip.process_options=0         
net.inet.ip.random_id=1               
net.inet.ip.redirect=0                
net.inet.ip.accept_sourceroute=0      
net.inet.ip.sourceroute=0             
net.inet.icmp.bmcastecho=0            
net.inet.icmp.maskfake=0              
net.inet.icmp.maskrepl=0              
net.inet.icmp.log_redirect=0          
net.inet.icmp.drop_redirect=1         
net.inet.tcp.drop_synfin=1           
net.inet.tcp.ecn.enable=1             
net.inet.tcp.fast_finwait2_recycle=1  
net.inet.tcp.icmp_may_rst=0           
net.inet.tcp.maxtcptw=15000           
net.inet.tcp.msl=5000                
net.inet.tcp.path_mtu_discovery=0     
net.inet.tcp.rfc3042=0                
net.inet.udp.blackhole=1              
net.inet.tcp.blackhole=2              
net.inet.ip.rtexpire=60      
net.inet.ip.rtminexpire=2    
net.inet.ip.rtmaxcache=1024
This tutorial is provided as is and I take no responsability for any damage caused by following these instructions improperly. However, I will try to help as much as I can if you have any issue with my tutorial.

Thanks to Tim for the original pf.conf file and tips.
09/02/2013 05:01 Metin2 Team#2
That's really cool.

Thank you for sharing this with us.


I really appreciate your effort and spirit.

I'm glad to be the first.
09/02/2013 08:37 TheRzR#3
Very good explained.
09/02/2013 09:47 Mi4uric3#4
Well done BigSox, most of the community has grown up with Microsoft Windows and has no/few experience with other OSs and their configuration. Helping to secure servers is a very important thing, thanks for contributing!
09/02/2013 11:00 Azuko#5
Good work :)
09/02/2013 23:52 Pulp310#6
thanks juan

why not S/SAFR keep state ?

Quote:
Only tcp connections use the "flag" directive, udp and icmp connections can not. For stateful connections, the default in PF is flags set to S/SA. This means, out of SYN and ACK, exactly SYN may be set. SYN, SYN+PSH and SYN+RST do match, but SYN+ACK, ACK and ACK+RST do not. The safer flag settings are S/SAFR as we have in the example. This will deny packets who have the SYN+FIN and SYN+RST flags set since they are generally illegal combinations.
09/02/2013 23:54 #SoNiice#7
Aren't there already much tutorials like this?
09/03/2013 00:06 .Shōgun#8
Quote:
Originally Posted by .CHSoNiice View Post
Aren't there already much tutorials like this?
Show me a tutorial written by someone who actually has some idea about it and not a copy & paste from somewhere else, and in english.

There isn't.

Also, you seem to have some kind of grudge against me since you post the same thing on all my threads. It's funny because I should be the one holding a grudge since you hacked metin2.sg 3 years ago when I was a Gm there.
09/03/2013 00:08 Pulp310#9
he's a typical epvp user..

btw there's no macro for this in your e xample

Code:
pass in on $ext_if proto tcp to any port $public_ports flags S/SA keep state \
        (max-src-conn 40, max-src-conn-rate 20/5, overload <abusive_hosts> flush)
09/03/2013 21:02 worldend#10
Give us any more protection for BSD. :)
09/03/2013 21:07 #SoNiice#11
Quote:
Originally Posted by Uncorrupted View Post
Show me a tutorial written by someone who actually has some idea about it and not a copy & paste from somewhere else, and in english.

There isn't.

Also, you seem to have some kind of grudge against me since you post the same thing on all my threads. It's funny because I should be the one holding a grudge since you hacked metin2.sg 3 years ago when I was a Gm there.
I never posted anything on your threads, I didn't try to attack you with this, I just asked :/

And I never "hacked" Metin2.sg - I just used a little exploit for having some fun :p
09/03/2013 22:36 xGreeny#12
Super geworden :)
09/06/2013 16:35 BlackVol4ara#13
Quote:
# service pf start
Enabling pf/etc/pf.conf:31: macro 'public_ports' not defined
/etc/pf.conf:31: syntax error
/etc/pf.conf:35: syntax error
pfctl: Syntax error in config file: pf rules not loaded
.
how fix HELP pls
09/08/2013 23:02 gemini300#14
just remove from script
pass in on $ext_if proto tcp to any port $public_ports flags S/SA keep state \
(max-src-conn 40, max-src-conn-rate 20/5, overload <abusive_hosts> flush)

add to /etc/rc.conf
pf_rules="/etc/pf.conf"
and then run /etc/rc.d/pf start

for service port its good to add port 25 53 80 3306 ports if you use www,mysql services
09/09/2013 04:26 .Shōgun#15
There were some "bugs" in the pf.conf file and I didn't have time these days for epvp.

I will edit the first post in a few minutes and add our sysctl.conf file as well which helps against some attacks.

And if some wannabe hacker is worried his booter won't work if people start taking this kind of measures, you know the way out...