Running an IRC server with CentOS 7 and ircd-hybrid

July 6, 2018

What is IRC?

IRC is Internet Relay Chat. It is a protocol which allows for chatrooms like Discord or Slack. It has a client-server model where users connect their clients to a server running an IRC service.

What is CentOS?

CentOS is a GNU/Linux based operating system. It is similar to Red Hat and Fedora. One of the key features of CentOS is that it has a long support life - each version will be supported for the 10 years following its release.


Getting CentOS 7

I downloaded the CentOS 7 x86_64 (64 bit) minimal ISO file here. It is around 900MB. I will also be installing it locally on a virtual machine using VirtualBox, however this will also work if installing on real hardware or in a cloud provider like Amazon AWS or Google Cloud.

CentOS 7 Installation

The CentOS installer is great, it configures everything for you. All I had to do was set a root password. When you boot to the command line however, the first thing we'll notice is we don't have internet access. Following the instructions in the References easily fixes this.

ircd-hybrid Installation

The first step is downloading ircd-hybrid. The official download link on their website is to SourceForge, so I will download the latest release from their GitHub.

curl https://codeload.github.com/ircd-hybrid/ircd-hybrid/tar.gz/8.2.24 > ircd-hybrid-8.2.24.tar.gz 

CentOS 7 minimal doesn't come with a C compiler installed, so I will install gcc.

yum install gcc

We can now begin the actual build process for ircd-hybrid.

tar -xzf ircd-hybrid-8.2.24.tar.gz
cd ircd-hybrid-8.2.24
./configure
make
make install

By default, ircd-hybrid installs itself to /usr/local/bin/ircd-hybrid/.

ircd-hybrid Setup and Configuration

Installing ircd-hybrid by compiling the source doesn't start us off with any default configuration files. The files we're going to have to make are ircd.conf and ircd.motd.

I'll start by downloading an example ircd.conf.

curl -k https://raw.githubusercontent.com/gimite/web-irc-util/blob/master/ircd-hybrid/ircd.conf > /etc/ircd.conf

That's a good start, but we'll need to make some changes. I'm using vi to edit this file.

Within the serverinfo block, I changed the name and description.

Within the administrator block, I changed the description, name, and email.

Within the operator block, we're going to change a few things. The name will be the username of our operator account. This will be the user who has configuration privileges on the IRC server. I named mine "root". The user field will be an IP whitelist allowing access to the operator account. It will be in the format *@192.168.*.* where * ie. the asterisk character is a wildcard. In my example, any IP from 192.168.0.0 to 192.168.255.255 will be able to log in if they have the operator credentials. You can set the IP to *@127.0.0.1 to only allow the local machine to access the operator account.

Lastly we'll need to set up the operator password. ircd-hybrid stores this as a Unix-style crypt hash. We are provided with a utility which will generate this for us. ircd-hybrid installs a program mkpasswd to the /usr/local/bin/ directory.

/usr/local/bin/mkpasswd -5 -p PASSWORD >> /etc/ircd.conf

I'm appending it to the end of our ircd.conf so it will be easy to move it to the correct spot using vi - with our raw terminal, we can't select, copy, or paste text as we would in a fully graphical environment.

vi /etc/ircd.conf

I'll use type ]] to navigate to the end of the file, and then v$hd to cut our hash into vi's buffer. Then simply type

/XX
"_dt"
P

to replace our password of XXXXX with our new hash.

An aside about those vi commands: v$hd goes: v to enter visual mode, $ to navigate to the end of the line, h to move one character to the left (so as to not cut the trailing newline) and then d to cut into vi's default register. /XX searches for the pattern XX, which should find password = "XXXXX";. "_dt" then specifies the _ register, uses d to cut, uses t to specify "until a character", and then the final " denotes the character to cut until - so it gets all 5 Xs. We then use P to paste from our register into the current cursor position.

ircd-hybrid won't run as root, so we'll need to run ircd as the user nobody.

/sbin/runuser -s /bin/sh - nobody -c '/usr/local/bin/ircd -configfile /etc/ircd.conf -logfile /var/log/ircd/ircd.log'

To see if our server is now running, we can check our listening ports using netstat. Netstat doesn't come preinstalled on the minimal CentOS installation, so I installed it with yum.

yum whatprovides "*/netstat"
yum install net-tools
netstat -antp

You should see ircd listening on port 6667.

To make ircd-hybrid start with this configuration every time the system boots, we will make a script for /etc/init.d/. init.d scripts must include start, stop, restart, and force-reload functionality. I'm going to do this with a perl script.

#!/bin/perl
# chkconfig: 345 90 60
use warnings;
use strict;

my $arg = shift;
die("Usage: ircd {start|stop|status|restart|force-reload}") if !$arg;

sub start {
        my $line = `netstat -antp | grep ircd`;
        if ($line) {
                print "ircd already started\n";
        } else {
                my $res = `/sbin/runuser -s /bin/sh - nobody -c '/usr/local/bin/ircd -configfile /etc/ircd.conf -logfile /var/log/ircd/ircd.log'`;
                if ($res =~ m/running in background mode/) {
                        print "ircd service started\n";
                        return 0;
                }
        }
        return 1;
}

sub stop {
        my $pid = `pidof ircd`;
        if (!$pid) {
                print "ircd not running\n";
                return 1;
        } else {
                `kill \$(pidof ircd)`;
                return 0;
        }
        return 1;
}

if ($arg eq "start") {
        exit start();
} elsif ($arg eq "stop") {
        exit stop();
} elsif ($arg eq "restart") {
        stop();
        exit start();
} elsif ($arg eq "force-reload") {
        stop();
        exit start();
} elsif ($arg eq "status") {
        if (!!`pidof ircd`) {
                print "RUNNING\n";
        } else {
                print "STOPPED\n";
        }
} else {
	print "Usage: ircd {start|stop|status|restart|force-reload}\n";		
}

I wrote this script on my main machine, and then downloaded it from my GitHub on my CentOS virtual machine. The necessary bits are the start, stop, reload functions, and the chkconfig line. The 345 is the run levels, the 90 is the start order, and 60 is the kill order. I don't really understand what they mean, but it works.

cd /root
curl -k https://raw.githubusercontent.com/Djent-/Djent-.github.io/master/blog/posts/ircd > ircd
cp ircd /etc/init.d/
mkconfig --add ircd
service ircd restart

Now when we reboot or poweroff our CentOS machine, ircd will start during boot. I took this time to add a second virtual network interface to my CentOS virtual machine (in addition to my NAT interface) so I can have a host-only connection to my VM.

So even though we've got ircd-hybrid listening on port 6667, that doesn't mean anyone can actually get there. From my host machine, I can ssh into my CentOS virtual machine just fine through my host-only adapter, but I can't reach port 6667 at all. Let's open up that port on the firewall.

firewall-cmd --get-active-zones
firewall-cmd --zone=public --add-port=6667/tcp --permanent
firewall-cmd --reload

Now we can reach our IRC server from the outside world!

IRC Channel Setup

I used the IRC client irssi to connect to my new server.

irssi
/connect 192.168.56.101
/join #test
hello!

References