New project: ZNC IRC bouncer log viewer

I've just published a new project on GitHub, named znc-log-viewer, that might be useful for IRC junkies.

If you use the ZNC IRC bouncer to keep you logged on to IRC all the time, you might've enabled the log module to avoid missing messages when you're not connected to the bouncer.

Searching those log files have always been a hassle, because they are located deep inside the .znc directory, and there are a lot of files stored in one big directory, which makes it hard to get an overview when you want to pull out your trusty friend, grep.

If you actually bothered to use grep, you would also notice that a single log file has a lot of server messages in it, that is generally not interesting when you're trying to figure out what has happened since the last time you were online. In my case, I just want access to the conversations that have been going on.

So if this problem is something you can relate to, feel free try out my new tool. If you find any problems with it, please open up an issue on the GitHub page.

Solved: ASUS P8Z68-V PRO GEN3 mainboard resetting instead of booting first device

I recently upgraded my main computer to a new shiny Intel Z68-based motherboard with a 2nd generation Core i7. A really nice piece of hardware, I'd say.

But while I was setting it up I had some very odd problem. When I plugged everything in and wanted to boot it, it just didn't want to boot any devices (but the EFI BIOS loaded without problems), it reset instead.

At first I thought I had a power problem, so I went out and bought a bigger PSU. But it still reset instead of booting. Then I called a friend and he thought the SATA controller might be busted. So he suggested unplugging everything and trying one part at the time.

After doing a lot of cross-testing I figured out that it was the USB cable to my APC Smart-UPS 1000 that stopped the boot from processing. So obviously either my UPS or motherboard firmware is incompatible with each other. Luckily I was not dependent on having the UPS USB cable connected, so I just disconnected it to avoid the problem. With that component disconnected everything worked as expected.

Moral of the story: Test with one component at the time if you're experiencing difficulties.

How to fix "No access" error when changing Windows file permissions

Yesterday I helped my father to install his new computer with Windows 7. For several reasons I shall not mention, it was in the best interest to take the hard drive of the old (broken) computer and copy all the data from it to the new. What he (and me) wanted was to keep all the settings and other stuff and just reinstall his programs. That meant copying the entire AppData folder under his user account in addition to his normal files.

During this process obviously all files had kept the old SIDs, and as they weren't matching his new SID (on the new computer) I was having problems accessing the files. Lots of stuff didn't work. I was getting "No access" messages left and right when I tried to change the permissions of those copied files. That is when it dawned on me that even though his user account was registered as an administrator, it wasn't able to change the permission bits on those files.

To avoid having to mess around forever to reset permissions to default inherited ACL on all those files (around 30000 or so of them) I dug a bit around on the Internet and found out that there is a command in Windows 7 called icacls.exe that works very much in the same way as chmod on Linux, just that it supports NTFS ACLs.

After reading around I found a forum post that mentioned it, and was redirected to Microsoft's knowledge base article on icacls.exe. After looking over that one I found this command line that solved everything.

cd C:\Users\username
icacls * /reset /T

The /T switch makes it run recursively. /reset, as the KB article explains, replaces the ACL on each file and folder with the default inherited ACL that just uses the ACL on the parent folder.

The last thing that was required was to run this command inside a cmd.exe shell with elevated privileges. You can do that by finding the Command Prompt icon in your start menu and right-clicking "Run as administrator".

Be aware that mucking around with ACLs, if you don't know what you're doing, can seriously break your system in more ways than you can think of. It can also open you up to various attacks because of more relaxed permissions.

If you like what you just read, please subscribe to the feed or follow me on Twitter or any of the other networks I'm registered in to be updated when I post something new.

Config::Role - Object constructor parameters from file made easy

After I wrote that big 5-part article on WWW::LastFM / XML::Rabbit I noticed several things that could be improved. One of them was the fact that loading configuration information from a file in the home directory was a pretty generic thing to do. I decided to factor that code out and release it as a separate CPAN module that can be used by any Moose class.

If you look at the code used to read the configuration information in the article mentioned above you'll see that it has improved quite a bit. The code below is shorter, but does the same thing as the old code.

package WWW::LastFM;
use Moose;
use namespace::autoclean;

# Read configuration from ~/.lastfm.ini,
# available in $self->config
has 'config_filename' => (
    is         => 'ro',
    isa        => 'Str',
    lazy_build => 1,
);
sub _build_config_filename { '.lastfm.ini' }
with 'Config::Role';

# And here we have our api key and secret
has 'api_key' => (
    is         => 'ro',
    isa        => 'Str',
    lazy_build => 1,
);
sub _build_api_key {
    return (shift)->config->{'API'}->{'key'};
}

has 'api_secret' => (
    is         => 'ro',
    isa        => 'Str',
    lazy_build => 1,
);
sub _build_api_secret {
    return (shift)->config->{'API'}->{'secret'};
}
...

The reason this approach is quite nice, is because it allows you to load e.g. username and password from a configuration file with the ability to override it in the constructor. You can also quite easily override the location to search for the configuration file in your tests by mocking the location returned by File::HomeDir->my_data(). Alternatively, you can specify either the config_file or config_files constructor parameters to explicitly specify the path to your configuration file (or an array reference of them).

I usually start my test case with code like this to override where to look for the configuration file for the test environment. Then I just put a copy of my configuration file inside the t folder with the same file name as usual.

# Mock home/config dir location
{
    use File::HomeDir;
    no warnings 'redefine';
    sub File::HomeDir::my_data { return 't'; }
}

The configuration file is loaded via Config::Any->load_files(), so you can use any format supported by that module. Your config attribute will always be represented as a hash reference.

If you find this article or the CPAN module Config::Role useful I'd be very happy if you share it with your friends on Facebook, Google+, Twitter or other service you use. If you like what you see, follow me on any of the networks at the top of the page of my blog and subscribe to my feed to keep informed on when I post something new.

How to automatically block IPs that do a dictionary attack on your SSH server

Have you ever noticed that the sshd on your publicly facing machines gets bombarded with dictionary attacks several times per day? This problem is mostly an annoyance, as it fills up the logs with lots of User authentication failed, wrong password for <username> messages. There are of course several ways to work around this problem, and the most common one is to run sshd on another port than 22. I find that approach cumbersome, because it means you'll always have to configure your client software to connect to a non-standard port, and in lots of cases a firewall at your location might be blocking the traffic as well. Isn't there a way to block these bothersome users instead?

I recently read an article in Linux Journal #210 that talked about a new feature in the Linux kernel called ipset. It allows you to create sets that store IP addresses which can dynamically be added to and removed from. This sets can be configured as selectors in iptables rules, so that you can perform actions on any IP address in the set, like dropping the packets. You can also create iptables rules that add or remove an IP from a set.

In Debian it is straight-forward to install ipset. Type in these commands to install ipset and the required kernel module. It should ensure it is automatically recompiled whenever you do a kernel upgrade.

$ apt-get install ipset xtables-addons-source
$ module-assistant auto-install xtables-addons

I asked around on IRC if it was possible to make sshd execute a shell script once the amount of logins from an IP went above some configurable threshold, but apparently it is not possible. Someone pointed me at fail2ban which is a system that scans your syslog looking for failed logins and turn them into blocking iptables rules (and probably more, I didn't look very closely). I thought that this was too slow, as I wanted something that triggered as soon as multiple failed logins for a user reached a certain threshold, but I wanted the block to be temporary, not permanent.

That is when I remembered that syslog (rsyslog in my case) can be configured to run the log messages through a program. I put together the program below that reads incoming messages from rsyslog with auth.info facility/level (default for sshd on Debian) and does the necessary things to ensure the offending IP is added to my autoblock ipset if it triggers a certain amount of failed logins in a short period. The autoblock ipset uses the iptree storage module that has a --timeout parameter to automatically purge entries from the set after a given time. I set it to 3600 seconds (1 hour).

What is also quite cool, is that I have a rule that will immediately put the IP of of anyone that tries to connect to my SMTP port (I don't run a mail server on my firewall) on the autoblock list. This particular bit happens completely inside netfilter, so its effect is immediate. Bye bye spammers! Try to connect to my (non-existent) email server and you're instantly blocked for an hour. And you didn't even know what hit you. :)

The reason I like the temporary block is that sometimes I port-scan my own server or do other strange things with it from remote computers, and the fact that I know the block will be lifted after an hour means I can continue without having to get physical access to server to remove the block. I can just smack myself in the forehead and wait an hour and continue whatever stupid thing I was doing.

PS: Remember that lots of IRC servers like to port-scan your IP when you connect to them, so you might need to put up some exceptions for those if you're an active IRC user and your particular IRC server likes to probe the SMTP port.