IPs ban on Linux

Ban Hammer

Who needs a quick ban?

Today we had a bruteforce attack on our nginx server. Well cannot say he was anywhere near successful though, the guy did POST /wp-login.php several times per second and all he got as an answer was 404. Fat chance…

But still, he had our access logs growing far larger than they usually do. So I tried to ban him. Unfortunately nginx does not use TCP wrappers by default (you can use ngx_tcpwrappers although it will have to be rebuilt from source).

So I made a little script, called ban-hammer to temporarily ban IPs using IPTables. There is also a cron.daily script to unban IPs each day. The script requires rpnc, but it is easy to adapt without it.

These scripts add and remove the IPs into a special IPT chain (which you can configure in the script). So you also have to configure your firewall to jump to the two chains and load banned IPs on boot:

echo "Bans"

load_bans() {
  ban_table=$1
  ban_chain=$2
  iptables=$3

  $iptables -N $ban_chain

  while read ban
  do
    ip=$(echo "$ban" | cut -d'=' -f 1)
    $iptables -A $ban_chain -s "$ip" -j DROP
  done < "$ban_table"

  $iptables -A INPUT -j $ban_chain
}

load_bans /etc/firewall/ip4.ban IP4BAN iptables
load_bans /etc/firewall/ip6.ban IP6BAN ip6tables

FP comparison in Shell

People tend to not like Shell. But I do!
Here is a simple example, try this floating point comparison:

$ [ 0.1 -gt 0.01 ]
[: 0.1: bad number

The shell itself cannot use float.
But there are multiple workarounds. Here is the one I prefer:

if rpnc "$a" "$b" - | grep "^-" > /dev/null
then
  echo "a < b"
fi

Although you may not have the rpnc command, so here is another one:

if [ $(echo "$a < $b" | bc) -eq 1 ]
then
  echo "a < b"
fi

ISP y u no DNSSEC?

Unbound is a secure, lightweight and high performance validating, recursive, and caching DNS resolver. It performs DNSSEC validation and it is also really easy to configure. Although it cannot act as a full fledged authoritative server, you may take a look at NSD, which is, on the contrary, authoritative only. For a nice tutorial about unbound configuration, see this post.

Today I discovered local_unbound on FreeBSD. This script generates a configuration suitable for running unbound as a forwarding resolver. It also uses resolveconf to update the list of forwarders. This means that it is automatically configured with the name servers provided by the DHCP offer.

By default, unbound is configured to withheld the reply from the client when the validation fails. Unfortunately most of the name servers provided by home routers and ISPs do not support DNSSEC. Even worse, some ISPs redirect all queries to their own name servers which of course do not support DNSSEC either. You can check if it is the case with this command:

dig @8.8.8.8 +short test.dnssec-or-not.net TXT

As Google public DNS support DNSSEC. If it does not show you anything, it is OK. If instead it says something like: “Nope!  DO bit not set in your query” then your query has been forwarded to a server which is not DNSSEC capable.

Because of this, you often end up with a nice caching forwarding resolver which does not seem to resolve anything (at least on the client side) because of bogus validations.

You have two solutions to overcome this. First you can force your forwarders to DNSSEC capable servers such as Google public DNS (8.8.8.8 / 8.8.4.4). However, as mentioned above this does not work when your ISP redirect all queries to its own server. The second solution is to configure unbound into permissive mode (/etc/unbound/unbound.conf):

server:
    (...)
    val-permissive-mode: yes

In that case, replies to queries that did not pass validation are not longer withheld from the client but the Authenticated Data bit is not set in the reply.

New series: Today’s movie

In a preceding article (ChangeLog), I said that I might post more on different subjects than what I usually post. So as part of this perpetual opening initiative, I will soon start a new series called “Today’s movie“. In which I tell you about a movie I am about to watch, what I thought of it (for what it’s worth), why you should drop everything you are doing right now to see it, or not.

You may like this, or not.
And you may also flame in the comments if you don’t agree.
Well I hope you’ll like it though.

As for me it will be an opportunity to revisit movies I didn’t see in a while.

Configure audio devices on VirtualBox

I recently installed a new Debian guest on a FreeBSD host with VirtualBox. On this VM I need to be able to play/record sound from my laptop (Skype). To do so I configure the guest with an Intel HDA soundcard using the OSS audio driver. However I want to use the internal mic (/dev/dsp1.0) which is different than the default unit (/dev/dsp). So I had basically two options. Either I could record my voice but could not hear anything or I could hear everything but could not record my voice.

But there is a solution! I digged in the VirtualBox source code, and there are actually some options for the OSS driver (and other audio drivers as well). The two options of interests are:

  • DACDev: Path to the DAC (output/playback) device.
  • ADCDev: Path to the ADC (input/record) device.

You can use VBoxManage to configure these options. Assuming that the name of the VM is MyVM with an Intel HDA card and the OSS driver, use this command:

$ VBoxManage setextradata MyVM "VBoxInternal/Devices/hda/0/LUN#0/Config/Audio/OSS/ADCDev" /dev/dsp1.0

You can also directly edit the vbox file for this VM:

MyVM.vbox:

<ExtraData>
  ...
  <ExtraDataItem name="VBoxInternal/Devices/hda/0/LUN#0/Config/Audio/OSS/ADCDev" value="/dev/dsp1.0"/>
</ExtraData>

Note if when starting the VM you receive the message The attached driver configuration is missing the 'Driver' attribute (VERR_PDM_CFG_MISSING_DRIVER_NAME). This is probably because the sound device you selected for this VM is not the same as specified in the extra data. The above example is for Intel HD Audio (hda). If you need ICH AC97, replace hda by ichac97 in the example above.

FreeBSD suspend and ttys.

I use FreeBSD 11-CURRENT on a Thinkpad X201 laptop. I said in a preceding post (Hello FreeBSD!) that although the Intel KMS driver works, I did not have access to the ttys and also that suspend and resume did not work.

This is no longer the case! I rebuiIt world two days ago (r274088) and I now have access to the ttys, and suspend/resume also works without any apparent problem (thanks to KMS/VT (NewCons) I guess). FreeBSD 11 is going to be great!

Nginx home directories and PHP

I use nginx as my main HTTP server.  I want the users to be able to publish their own pages in a special directory (public_html) within their home directory. They should also be able to use PHP scripts if they want to. You can access the user webpage (that is the content of their public_html directory) with this URL: http://[server]/~[user]/. Here is a snippet of the configuration I use to do so:

index index.html index.xml index.php;

# PHP in home directory
location ~ ^/~(.+?)(/.*\.php)(.*)$ {
  alias /home/$1/public_html;

  try_files $2 =404;
  fastcgi_split_path_info ^(.+\.php)(.*)$;
  fastcgi_pass unix:/var/run/php5-fpm.sock;
  fastcgi_index index.php;
  fastcgi_intercept_errors on;
  include fastcgi_params;

  fastcgi_param SCRIPT_NAME /~$1$fastcgi_script_name;
}

# Home directories
location ~ ^/~(.+?)(/.*)?$ {
  alias /home/$1/public_html$2;
}

You can see here the two locations that match the user directories. The first one matches the PHP scripts and passes them to the FastCGI process manager. For more information, see PHPFcgiExample. Note that I use a UNIX instead of an INET socket. Why would you bother IP on localhost when you can use an UNIX socket? I also set the SCRIPT_NAME parameter to ensure that it is derived correctly from the user URL. This need to be fixed for pages that point to themselves. I also had to restart php5-fpm to ensure that the changes were taken into account.