Skip to content

Commit

Permalink
Merge branch 'master' into next
Browse files Browse the repository at this point in the history
  • Loading branch information
thesamesam committed Oct 16, 2016
2 parents bd57ef1 + 500ac13 commit 55878bd
Show file tree
Hide file tree
Showing 26 changed files with 488 additions and 157 deletions.
4 changes: 3 additions & 1 deletion Makefile.PL
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,16 @@ perl_version '5.020';

all_from 'lib/IRCd/Client.pm';
requires 'IO::Socket::SSL';
requires 'IO::Epoll';
recommends 'IO::Epoll';
recommends 'IO::KQueue';
requires 'XML::Simple';
requires 'Term::ANSIColor';
requires 'Net::DNS';
requires 'Datetime';
requires 'Path::Tiny';
requires 'Getopt::Long';
requires 'Module::Install';
requires 'Try::Tiny';
requires 'String::Scanf';
requires 'Tie::Refhash';

Expand Down
17 changes: 4 additions & 13 deletions README
Original file line number Diff line number Diff line change
@@ -1,41 +1,32 @@
<h1>cmpctircd</h1>

<h2>About</h2>

<p>The aim of this project is to provide a stable, fast, and <em>modern</em> ircd.</p>

<h2>Status</h2>

<p>For now, it is still under heavy development. It will be clear when it is production ready.
<a href="https://bugs.cmpct.info/">Bugzilla</a> is a good indicator of progress.</p>

<p>Checkout <em>master</em>, edit <code>ircd.xml</code>, and run <code>bin/ircd --config ircd.xml --motd ircd.motd --rules ircd.rules</code> to test.
Windows is untested as of yet, but it should run with <code>select</code> as the socket provider (<code>&lt;sockets:provider&gt;</code>). <code>epoll</code> is
recommended on Linux.</p>

<p>Use parameter <code>--loglevel $LEVEL</code> where $LEVEL is one of: DEBUG, WARN, INFO, ERROR to control the logging level.</p>

<p>TLS certs and keys should be 'tls_cert.pem' and 'tls_key.pem' respectively. Install with <code>./Makefile.PL; make; sudo make
install</code>.</p>

<h2>Dependencies</h2>

<ul>
<li>Net::DNS (libnet-dns-perl, only if <code>&lt;advanced:dns&gt;</code> is enabled)</li>
<li>IO::Socket::SSL (libio-socket-ssl-perl, only if <code>&lt;server:tls&gt;</code> is enabled)</li>
<li>IO::Epoll (libio-epoll-perl)</li>
<li>IO::Epoll (libio-epoll-perl, only if <code>&lt;sockets:provider&gt;</code> is <code>epoll</code>)</li>
<li>IO::KQueue (N/A, only if <code>&lt;sockets:provider&gt;</code> is <code>kqueue</code>)</li>
<li>XML::Simple (libxml-simple-perl)</li>
<li>Datetime (libdatetime-perl)</li>
<li>Path::Tiny (libpath-tiny-perl)</li>
<li>Module::Install (libmodule-install-perl)</li>
<li>Try::Tiny (libtry-tiny-perl)</li>
<li>String::Scanf (install with CPAN)</li>
<li>Term::ANSIColor (within core on Debian)</li>
<li>Getopt::Long (within core on Debian)</li>
<li>Tie::Refhash (within core on Debian)</li>
<li><code>perl &gt;= 5.20</code> for <code>postderef</code></li>
</ul>

<h2>Contact</h2>

<p>Email me at sam@cmpct.info if you wish to contribute or you have questions.
An IRC server will be created once <em>cmpctircd</em> is ready to self-host -- <strong>soon</strong>.</p>
An IRC server will be created once <em>cmpctircd</em> is ready to self-host -- <strong>soon</strong>.</p>
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,13 @@ Dependencies
------------
* Net::DNS (libnet-dns-perl, only if `<advanced:dns>` is enabled)
* IO::Socket::SSL (libio-socket-ssl-perl, only if `<server:tls>` is enabled)
* IO::Epoll (libio-epoll-perl)
* IO::Epoll (libio-epoll-perl, only if `<sockets:provider>` is `epoll`)
* IO::KQueue (N/A, only if `<sockets:provider>` is `kqueue`)
* XML::Simple (libxml-simple-perl)
* Datetime (libdatetime-perl)
* Path::Tiny (libpath-tiny-perl)
* Module::Install (libmodule-install-perl)
* Try::Tiny (libtry-tiny-perl)
* String::Scanf (install with CPAN)
* Term::ANSIColor (within core on Debian)
* Getopt::Long (within core on Debian)
Expand Down
97 changes: 60 additions & 37 deletions bin/ircd
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use feature 'postderef';
use Path::Tiny qw(path);
use lib path($0)->absolute->parent->sibling('lib')->stringify;
use Getopt::Long;
use IO::Epoll;
use IO::Socket::INET;
use DateTime;

Expand All @@ -21,11 +20,13 @@ use IRCd::Sockets::Epoll;
use IRCd::Socket;

package IRCd::Run;
# Try::Tiny has to be beneath the package definition, it seems.
use Try::Tiny;

sub new {
my $class = shift;
my $self = {
'config' => IRCd::Config->new(shift),
'config' => undef,
'listener' => undef,
'epoll' => undef,
'clients' => undef,
Expand All @@ -44,9 +45,11 @@ sub new {
'maxtargets' => undef,
};
bless $self, $class;
$self->{config} = IRCd::Config->new($self, shift);
$self->{motd_path} = shift;
$self->{rules_path} = shift;
$self->{config}->setupHandlers($self, shift);
$self->{mod_path} = shift;
$self->{config}->setupHandlers($self, $self->{mod_path});
return $self;
}

Expand All @@ -64,13 +67,13 @@ sub setup {
ReuseAddr => 1,
) or die $!;
$self->{clientListener}->blocking(0);
$self->{serverListener} = IO::Socket::INET->new(
LocalHost => $self->{config}->{ip},
LocalPort => 6661,
Listen => 5,
ReuseAddr => 1,
) or die $!;
$self->{serverListener}->blocking(0);
#$self->{serverListener} = IO::Socket::INET->new(
# LocalHost => $self->{config}->{ip},
# LocalPort => 6661,
# Listen => 5,
# ReuseAddr => 1,
#) or die $!;
#$self->{serverListener}->blocking(0);
if($self->{config}->{tls}) {
require IO::Socket::SSL;
$self->{clientTLSListener} = IO::Socket::SSL->new(
Expand All @@ -81,11 +84,10 @@ sub setup {
Listen => 5,
ReuseAddr => 1,
) or die $!;
$self->{clientTLSListener}->blocking(0);
$self->{clientTLSSelector} = $self->{config}->getSockProvider($self->{clientTLSListener});
}
$self->{clientSelector} = $self->{config}->getSockProvider($self->{clientListener});
$self->{serverSelector} = $self->{config}->getSockProvider($self->{serverListener});
#$self->{serverSelector} = $self->{config}->getSockProvider($self->{serverListener});
$self->{clients} = {
id => {},
uid => {},
Expand All @@ -110,30 +112,45 @@ sub setup {
$self->{log}->info("Starting cmpctircd");
$self->{log}->info("==> Host: $self->{host}");
$self->{log}->info("==> Listening on: $self->{ip}:$self->{port}");
if($self->{config}->{tls}) {
$self->{log}->info("==> Listening on: $self->{ip}:$self->{config}->{tlsport} (TLS)");
}
}

sub run {
my $self = shift;
while(1) {
### ###
### Client loop ###
### ###
$self->clientLoop($self->{clientListener}, $self->{clientSelector}, 1024);
try {
while(1) {
### ###
### Client loop ###
### ###
$self->clientLoop($self->{clientListener}, $self->{clientSelector}, 1024);

### ###
### Client (TLS) ###
### loop ###
### ###
if($self->{clientTLSListener}) {
# http://search.cpan.org/~sullr/IO-Socket-SSL-2.036/lib/IO/Socket/SSL.pod#Common_Usage_Errors
$self->clientLoop($self->{clientTLSListener}, $self->{clientTLSSelector}, 16000, 1);
}
### ###
### Client (TLS) ###
### loop ###
### ###
if($self->{clientTLSListener}) {
# http://search.cpan.org/~sullr/IO-Socket-SSL-2.036/lib/IO/Socket/SSL.pod#Common_Usage_Errors
$self->clientLoop($self->{clientTLSListener}, $self->{clientTLSSelector}, 16000, 1);
};

### ###
### Server loop ###
### ###
$self->serverLoop($self->{serverListener}, $self->{serverSelector}, 1024);
}
### ###
### Server loop ###
### ###
#$self->serverLoop($self->{serverListener}, $self->{serverSelector}, 1024);
};
} catch {
$self->{log}->error("Caught a fatal exception: $_");
# Tell the users
my $host = $self->{host};
foreach(values($self->{clients}->{id}->%*)) {
my $mask = $_->{client}->getMask(1);
$_->{client}->write(":$self->{host} NOTICE $self->{host} :A fatal error occurred, causing the server to shutdown.");
$_->{client}->write(":$self->{host} NOTICE $self->{host} :Please contact the server administrator if you cannot reconnect within a few minutes.");
$_->{client}->write(":$self->{host} NOTICE $self->{host} :Server administrators: report this to https://bugs.cmpct.info/ if it persists.");
};
};
}

sub clientLoop {
Expand All @@ -143,10 +160,10 @@ sub clientLoop {
my $bytes = shift // 1024;
my $tls = shift // 0;

my @readable = $selector->readable(100);
my @readable = $selector->readable(0);
foreach my $event (@readable) {
# This is needed because of the way that IO::Epoll vs IO::Socket return handles (or fds)
$event = fileno($event) if(ref($event) eq 'IO::Socket::INET');
$event = fileno($event) if(ref($event) =~ /IO::Socket::(INET|SSL)/);
$event = $event->[0] if(ref($event) eq 'ARRAY');
if($event == fileno($listener)) {
# Accept a new client
Expand All @@ -167,7 +184,13 @@ sub clientLoop {
$socket->{client}->{server} = $self->{host};
if($self->{dns}) {
$socket->{sock}->write(":$self->{host} NOTICE * :*** Looking up your hostname...\r\n");
$socket->{client}->{query} = $socket->{client}->{resolve}->fire($socket->{client}->{ip});
$socket->{client}->{dns_time} = time();
# XXX: See bug 114
if(!$socket->{client}->{ip}) {
$self->{log}->debug("BUG! Got a client without an IP.");
return;
}
$socket->{client}->{query} = $socket->{client}->{resolve}->fire($socket->{client}->{ip});
} else {
# TODO: Could have a 'no DNS resolve enabled' message here.
# TODO: I think some servers do it?
Expand Down Expand Up @@ -219,7 +242,7 @@ sub serverLoop {
my $bytes = shift // 1024;
my $tls = shift // 0;

my @readable = $selector->readable(100);
my @readable = $selector->readable(0);
foreach my $event (@readable) {
# This is needed because of the way that IO::Epoll vs IO::Socket return handles (or fds)
$event = fileno($event) if(ref($event) eq 'IO::Socket::INET');
Expand Down Expand Up @@ -310,9 +333,9 @@ sub getClientByUID {


if(!caller) {
$SIG{PIPE} = sub {
print STDERR "SIGPIPE @_\n";
};
# The conditions causing a SIGPIPE are handled elsewhere (see write and read code)
# so make this a noop
$SIG{PIPE} = sub {};
my $config = "/etc/cmpctircd/ircd.xml";
my $motd = "/etc/cmpctircd/ircd.motd";
my $rules = "/etc/cmpctircd/ircd.rules";
Expand Down
14 changes: 9 additions & 5 deletions ircd.xml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@
</cloak>

<sockets>
<!-- Can be one of: epoll, select -->
<!-- Can be one of:
* epoll (Linux)
* kqueue (*BSD)
* select (most of anything)
-->
<provider>epoll</provider>
</sockets>

Expand All @@ -59,15 +63,15 @@
<advanced>
<requirepong>1</requirepong>
<dns>1</dns>
<dnstimeout>5</dnstimeout>
<pingtimeout>120</pingtimeout>
<maxtargets>200</maxtargets>
</advanced>

<opers>
<!-- Supported hash values: http://search.cpan.org/~mshelor/Digest-SHA-5.96/lib/Digest/SHA.pm#EXPORTABLE_FUNCTIONS -->
<!-- Supported hash values: sha1, sha256, sha512, and the ones inbetween. -->
<!-- https://wiki.cmpct.info/w/IRCd:Documentation/IRCops -->
<!-- See the wiki for descriptions of these parameters -->
<!-- Pick your own password! Default is 'password' for the 'sam' user. -->
<!-- Set tls='1' if you want tls-only opers. -->
<oper name='sam' password='5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8' hash='sha256'/>
<oper name='sam' password='5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8' hash='sha256' tls='0' host='*@*'/>
</opers>
</config>
20 changes: 10 additions & 10 deletions lib/IRCd/Ban.pm
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ package IRCd::Ban;
sub new {
my ($class, %args) = @_;
my $self = {
'nick' => $args{nick} // '*',
'user' => $args{user} // '*',
'host' => $args{host} // '*',
'setter' => $args{setter} // '*',
'time' => $args{time} // time(),
'nick' => lc($args{nick}) // '*',
'user' => lc($args{user}) // '*',
'host' => lc($args{host}) // '*',
'setter' => $args{setter} // '*',
'time' => $args{time} // time(),
};
bless $self, $class;
return $self;
Expand All @@ -27,11 +27,11 @@ sub match {
$user =~ s/\*/\.*/;
$host =~ s/\*/\.*/;

return 0 if($client->{nick} !~ $nick);
return 0 if($client->{ident} !~ $user);
return 0 if($client->{cloak} !~ $host
and $client->{host} !~ $host
and $client->{ip} !~ $host);
return 0 if(lc($client->{nick}) !~ $nick);
return 0 if(lc($client->{ident}) !~ $user);
return 0 if(lc($client->{cloak}) !~ $host
and lc($client->{host}) !~ $host
and lc($client->{ip}) !~ $host);
return 1;
}

Expand Down
25 changes: 18 additions & 7 deletions lib/IRCd/Channel.pm
Original file line number Diff line number Diff line change
Expand Up @@ -54,16 +54,27 @@ sub initModes {
my $client = shift;
my $ircd = shift;

# anonymous function to set, is independent of the XML hash logic
my $setter = sub {
my $self = shift;
my $name = shift;
my $param = shift;
if(ref($param) eq 'HASH') {
$param = "";
}
# we need to pass the client, otherwise the mode setting won't have a user to ref to
$self->{modes}->{$name}->grant($client, "+", $name, $param // undef, 1, 0);
};

# Set initial modes
foreach my $chanModes (values($ircd->{config}->{channelmodes}->%*)) {
foreach(keys($chanModes->%*)) {
my $name = $_;
my $param = $chanModes->{$name}->{param};
if(ref($param) eq 'HASH') {
$param = "";
# XXX: if there's only one mode, XML::Simple doesn't make 'name' the key (workaround)
if($chanModes->{name}) {
$setter->($self, $chanModes->{name}, $chanModes->{param});
} else {
foreach(keys($chanModes->%*)) {
$setter->($self, $_, $chanModes->{$_}->{param});
}
# we need to pass the client, otherwise the mode setting won't have a user to ref to
$self->{modes}->{$name}->grant($client, "+", $name, $param // undef, 1, 0);
}
}
}
Expand Down
Loading

0 comments on commit 55878bd

Please sign in to comment.