VnutZ Domain
Copyright © 1996 - 2024 [Matthew Vea] - All Rights Reserved

2013-10-17
Featured Article

How To Configure IRCd-Hybrid For SSL With STunnel

[index] [18,321 page views]
Tagged As: How To, IRC, Security, and Tutorial

Internet Relay Chat

IRC (Internet Relay Chat) dates back to 1988 when the first version was written by Jarkko "WiZ" Oikarinen in Finland. It was originally designed to extend existing BBSs (Bulletin Board Services) and provide a real-time chat service. Fundamentally, it is a multi-user, multi-channel, multi-server environment with no centralized control and is governed solely by the operators that choose to link their servers together. Various bickering between those operators resulted in a largely fragmented environment that peaked with major networks like EFNet, Undernet and the like. The system rapidly grew into the de facto standard for Internet chatting with estimates of more than 10 million users by 2003. While its still widely used, the dominant IRC networks have changed and many people simply operate their own networks. The prevalence of "common folks" on IRC greatly diminished with the rise in popularity of simpler chat networks.

Running an IRC server these days is a relatively simple task compared to the historical need to download source, make patches for compatibility, compile and beat your head against the wall for missing libraries. Just download the appropriate packages and edit the configuration files. It only gets tricky when you start integrating with other people.

Installing & Configuring IRCd-Hybrid

IRCd-Hybrid is based on the original IRCd source code and is easily available through the advanced packaging tool for Debian based Linux systems. Simply use the following command to download the server and install it with all of its necessary dependencies:

sudo apt-get install ircd-hybrid

The default configuration file that needs editing can be found at /etc/ircd-hybrid/ircd.conf. To simply get the server up requires very little updating and is equivalent to setting the M:, A:, I:, O: and P: lines on older IRC servers. IRCd-Hybrid takes a different approach to its configuration file using a more verbose format. But the required information is largely the same.

For the serverinfo{} section, the following fields were required for the server to function properly. The name and hub fields become more important later in the event your server connects with other IRC servers. Name is not necessary to be an FQDN. This is roughly equivalent to the old M: line in legacy configuration files but lacks the four digit SID field.


serverinfo {
	name = "irc.yourhost.com";
	description = "Company LLC";
	network_name = "Company";
	network_desc = "Company IRC";
	hub = yes;
	max_clients = 512;
};

Technically, you don't really need to populate the admin{} section. But it is the "right" thing to do for letting clients know who to contact for troubleshooting. It is equivalent to the old A: line in legacy configuration files.


admin {
	name = "SysAdmin";
	description = "Server Administrator";
	email = "";
};

The values in the class{} sections can generally be left default. There will usually be several of them. They are equivalent to the old Y: lines in legacy configuration files. Mostly, the class{} section is used for tuning. Sometimes, the ping_time field will become an irritant when troubleshooting with other IRC servers that are finicky about the field matching between the hosts.

The listen{} section instructs the server on what IP addresses and ports to bind. For a quick win, configure the line to read 0.0.0.0 which will bind to all available IPs. If your host is multi-homed and you only want one of the IP addresses to be IRC accessible, set the exact IP. More than one IP address can be defined simply by adding additional host = "1.2.3.4" lines as required. 6667 is the traditional IRC port, but its possible to define a range of ports using the .. syntax. This is equivalent to the old P: lines in legacy configuration files.


listen {
	host = "0.0.0.0";
	port = 6666..6668;
};

The auth{} sections can generally be left default. It is equivalent to the old I: lines in legacy configuration files and is used for defining what users may connect to the server. It's possible to restrict users based on the IP addresses they're connecting from in addition to defining usernames and passwords.

The operator{} section must be updated for security purposes. Its configuration controls the users allowed to administer the server from within an IRC client and establishes restrictions on special commands they may use. It is imperative to set the password field and makes good sense to change the name and user fields. Setting IP addresses on the user field limits what client IP addresses are allowed to use the operator privileges. The password is a hash and can be generated using the command:/usr/bin/mkpasswd password. The IRCd-Hybrid server supports stronger MD5 hashes and will recognize it automatically if one of those hashes is used instead. All of the remaining fields define the privileges associated to that operator. These settings are equivalent to the old O: lines in legacy configuration files.


operator {
	name = "IRC_Wizard";
	user = "*@127.0.0.1";
	password = "Dm0JXAmrUFyBs";
	class = "opers";
	global_kill = yes;
	remote = yes;
	kline = yes;
	unkline = yes;
	gline = yes;
	die = yes;
	rehash = yes;
	nick_changes = yes;
	admin = yes;
};

With the configuration file updated, simply restart the server to apply the settings:

sudo service ircd-hybrid restart

For comparison purposes, the following is an equivalent ircd.conf file for the IRCd-irc2 server which is the original IRC code base. It uses the older configuration format with cryptic looking M:, A:, I:, O:, and P: lines. Some people prefer its more condensed nature.


M:irc.yourhost.com::USA:6667:000A
A:yourname:sysadmin@yourhost.com:Company LLC:Company:
Y:1:120::100:2000000:5.5:100.100
I:*:::0:1
P::::6666:
P::::6667:
P::::6668:
O:127.0.0.1:Dm0JXAmrUFyBs:IRC_Wizard::1:A:

Connecting Multiple IRC Servers

The earlier configuration established a single, unencrypted instance of an IRC server. More than likely, that's good enough for most people's needs but linking servers together is what IRC is all about. Each server needs to have a corresponding connect{} section ... note, that is NOT matching, just corresponding. The following examples highlight sections from the ircd.conf file that are important to establish a working link.

Hypothetical Server One

serverinfo {
	name = "Hypothetical_One";
}

listen {
	host = "192.168.1.1";
	port = 6666;
};

connect{
	name = "irc.hyptothetical2.com";
	host = "10.0.0.1";
	port = 6667;
	send_password = "Password1";
	accept_password = "Password2";
	encrypted = no;
	hub_mask = "*";
	class = "server";
	compressed = no;
	autoconn = yes;
};
Hypothetical Server Two

serverinfo {
	name = "irc.hypothetical2.com";
}

listen {
	host = "10.0.0.1";
	port = 6667;
};

connect{
	name = "Hypothetical_One";
	host = "192.168.1.1";
	port = 6666;
	send_password = "Password2";
	accept_password = "Password1";
	encrypted = no;
	hub_mask = "*";
	class = "server";
	compressed = no;
	autoconn = yes;
};

The host and port fields should be obvious. They correlate to the distant end server's settings that can be found in the listen{} section. The less obvious pieces to ensure match are the name and password fields. Usually, the biggest troubleshooting problem comes from mismatched names. Take note of the name fields in the connect{} sections. It corresponds to the other server's name field from the serverinfo{} section. These strings must match otherwise the server's will not connect. Now note how the password fields are juxtaposed between the two servers. Simply make sure the send_password corresponds to the distant end's accept_password and vice versa. Lastly, the autoconn field will instruct the servers to automatically attempt connecting to each other.

In the original configuration, there was a class{} section with options to control the server's behavior. While not critical to making the server work, they allow for tuning. The connectfreq field defines how often the automatic connection attempts take place. As previously mentioned, sometimes the ping_time field has to match between servers.

For comparison purposes, the following are equivalent lines using the older configuration format that will link to each other. Again, as above only the relevant lines are included. This is an example that definitely benefits from the condensed nature. Note how C: and N: lines come in pairs on a host which accommodates for the send_password and accept_password paradigm.

Hypothetical Server One

M:Hypothetical_One::USA:6666:000A
P:192.168.1.1:::6666:
Y:9:120:300:5:20000000::
C:10.0.0.1:QspeGkKh.MU8c:irc.hypothetical2.com:6667:9::
N:10.0.0.1:orx5P5DQppLzA:irc.hypothetical2.com:6667:9::
Hypothetical Server One

M:irc.hypothetical2.com::USA:6666:000A
P:10.0.0.1:::6667:
Y:9:120:300:5:20000000::
C:192.168.1.1:orx5P5DQppLzA:Hypothetical_One:6666:9::
N:192.168.1.1:QspeGkKh.MU8c:Hypothetical_One:6666:9::

Enabling SSL

The most referenced resource for attempting to get SSL support natively back into the IRCd-Hybrid client is the MarvelServ article Setting Up ircd-hybrid and hybserv services with SSL on Ubuntu. A lot of websites and forums seem to be successful following those steps. Perhaps something has changed in the source, or maybe I just did everything wrong, but those instructions did not work for me. The gist of the steps are to install OpenSSL and the source code for IRCd-Hybrid.


sudo apt-get install openssl libssl-dev
sudo apt-get source ircd-hybrid

Next, browse into the IRCd-Hybrid source and locate the /ircd-hybrid-*/debian/rules file and modify it with the line USE_OPENSSL = 1 in order to enable SSL support. Following this step, recompile the server and package it for installation.


sudo dpkg-buildpackage -rfakeroot -uc -b
sudo dpkg -i ircd-hybrid_*.deb

Lastly, edit the /etc/ircd-hybrid/ircd.conf configuration file by adding two lines to the listen{} section. Set flags = ssl; and identify a port (port = 6697) for SSL connections. Restart the server and everything is supposed to work.

Installing & Configuring STunnel

The steps for including SSL support directly into IRCd-Hybrid did not work for me. So I opted for the STunnel solution. Essentially, STunnel acts like a man-in-the-middle handling all of the SSL connections and then passing off the unencrypted end to the destination server. It can be used to wrap just about any protocol and can be run in a variety of configurations. If not already present, it will be necessary to install the support utilities:


sudo apt-get install openssl stunnel4

First things first, encryption keys are necessary. These can be generated using the OpenSSL utilities as follows:

sudo openssl req -new -x509 -days 365 -nodes -config /etc/ssl/openssl.cnf -out stunnel.pem -keyout stunnel.pem

This command will produce the following output and prompts. Although its recommended to provide information such as country name and organization name, the mandatory field is the common name. Depending on the connecting client, sometimes the FQDN is required here.


Generating a 2048 bit RSA private key
......................................................................+++
................................................................................+++
writing new private key to 'stunnel.pem'
-----
You are about to be asked to enter information that will be incorporated into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:US
State or Province Name (full name) [Some-State]:N/A
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Company LLC
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:irc.yourhost.com
Email Address []:

The next step is to configure STunnel itself. Use and editor to open and modify the /etc/stunnel/stunnel.conf configuration file. Generally speaking, all of the defaults will be acceptable. But the following example will establish functionality:


; Protocol version (all, SSLv2, SSLv3, TLSv1)
sslVersion = SSLv3

; Some security enhancements for UNIX systems - comment them out on Win32
chroot = /var/lib/stunnel4/
setuid = stunnel4
setgid = stunnel4

; PID is created inside the chroot jail
pid = /stunnel4.pid

; Some performance tunings
socket = l:TCP_NODELAY=1
socket = r:TCP_NODELAY=1
compression = zlib

; Authentication stuff
verify = 1

; Some debugging stuff useful for troubleshooting
;debug = 7
;output = /var/log/stunnel4/stunnel.log

; Use it for client mode
;client = yes

; Service-level configuration
[irc]
cert    = /etc/stunnel/stunnel.pem
accept  = 6697
connect = 6667

The important points are to define the service for wrapping. Notice the [irc] section defines the encryption certificate generated earlier. It also contains fields for accept and connect which allow external hosts to make a secure, SSL connection to the accept port whereupon STunnel handles the encryption and passes the unencrypted link locally on 127.0.0.1 to the defined connect port.

That piece about passing the unencrypted data via a local connection is important. Depending on how the ircd.conf file was setup, a modification may be required. In the event the listen{} section bound all IP addresses using the 0.0.0.0 address than everything will work. However, if specific IP addresses were bound, then it will be necessary to add an additional line permitting binding 127.0.0.1 otherwise connections from STunnel to IRCd-Hybrid will be refused.

Now to actually enable STunnel. Use an editor and modify /etc/default/stunnel4 and set ENABLED=1 to activate. Save the file and restart the service using the command:

sudo service stunnel4 restart

At this point, hosts and appropriately configured servers can make SSL connections on port 6697. These are handled, but not processed by, STunnel. The utility merely acts as an encryption/decryption conduit and maintains a daisy-chained connection with the underlying IRCd-Hybrid server. This relationship allows IRCd-Hybrid to be blissfully unaware of the added SSL protections as its ircd.conf configuration is still setup for unencrypted communications. It would be wise at this point to restrict access to the IRCd-Hybrid server to only local connections to prevent unwanted cleartext from being transmitted. After all, if Alice connects via SSL to the IRC server but Bob does not, the IRC server will send Alice's messages unencrypted to Bob and defeat the entire purpose.

Connecting Multiple IRC Servers With SSL

At this point, the IRC server is running, linked to other IRC servers, and accepts inbound connections from STunnel. But it currently cannot initiate a connection to another server over SSL. Only a few small updates are necessary to make this possible. Start by editing the STunnel configuration file on "Hypothetical Server One" to add an additional service.


; Service-level configuration
[irc]
cert    = /etc/stunnel/stunnel.pem
accept  = 6697
connect = 6666

[irc-outbound]
client  = yes
cert    = /etc/stunnel/stunnel.pem
accept  = 6669
connect = 10.0.0.1:6697

The change here was adding a [irc-outbound] section. The client = yes field was added which lets STunnel know its not the receiving server in this case but the initiating client. The ports were setup to accept a connection from the local IRCd-Hybrid server on 6669 and then reach out to the distant end on port 6697. Note the IP address in the connect field can be replaced by fully qualified domain name. STunnel actually solves an irritant of the IRCd-Hybrid server in this regard. Normally, the IRCd-Hybrid server requires you to put an IP address in the connect{} section which is not helpful when the other server changes IP addresses. But STunnel doesn't require an IP so the distant end can use a dynamic DNS service.

Next, a simple change is required to the connect{} block of the IRCd-Hybrid configuration file.

Hypothetical Server One

serverinfo {
	name = "Hypothetical_One";
}

listen {
	host = "192.168.1.1";
	port = 6666;
};

connect{
	name = "irc.hyptothetical2.com";
	host = "127.0.0.1";
	port = 6669;
	send_password = "Password1";
	accept_password = "Password2";
	encrypted = no;
	hub_mask = "*";
	class = "server";
	compressed = no;
	autoconn = yes;
};

Make sure the defined port in the listen{} section does not conflict with the port added to the STunnel configuration file. In the example below, the IRCd-Hybrid server only listens on 6666 while STunnel listens on 6697 (forwarded to local 6666) and 6669 (forwarded to Hypothetical Sever Two).

Next, the connect{} section needs two edits. Change the host to the local loopback address and the port to 6669. This instructs the IRCd-Hybrid server to connect locally to STunnel instead of remotely to Hypothetical Server Two. What happens now is STunnel initiates the connection to an equivalent STunnel (or IRCd server with native SSL support) on the distant end, negotiates the SSL link, and encrypts all the traffic.

Finally, as an IRC operator, simply rehash the configuration file from the server and restart the STunnel service. It is now possible to connect to the IRC server as a client via SSL, receive connections from other IRC servers via SSL, and initiate connections to other IRC servers via SSL.



More site content that might interest you:

A fellow OmniNerd author wrote this snarky background on Halloween's origins.


Try your hand at fate and use the site's continuously updating statistical analysis of the MegaMillions and PowerBall lotteries to choose "smarter" number. Remember, you don't have to win the jackpot to win money from the lottery!


Tired of social media sites mining all your data? Try a private, auto-deleting message bulletin board.


paypal coinbase marcus