・ Web系SE募集 (技術開発部開発系エンジニア・Java/Tomcat 420万円~750万円)
   ・ 社内SE募集 (業務系システムの開発・社内イントラ)

PerlでSSL対応IRCサーバーの作り方(POE::Component::Server::IRC)

user-pic
0

POE::Component::Server::IRC を使用したIRCサーバーです。
POE::Component::Server::IRC は、現時点で最新の VERSION 1.38 を使用します。
 

POCo::Server::IRC を使うので実装は簡単です。
しかしこのバージョンには注意が必要ですのでその辺を記載します。

本題の前に、なぜ IRCサーバー立てるの?ってところから。
 
私は、IRCに関して詳しくは無く、IRCコマンドもほとんどわかりませんが、以前の職場でネタ系や情報共有などにIRCを使っていて良かったので
今の職場でも使いたいと思いました。
それで、今の職場にIRCの導入を進めようと思い、以前の職場でIRCサーバーを立ててた daiba先生 に、どうしたらいいか聞いてみたところ、
サーバーは、
で、Bot(URLのタイトルひろってくるやつ)は
と教えていただいたので、そこにあった、ngIRCd: Next Generation IRC Daemon を使うことにしました。
そして、社内への導入を進めていたのですが、浸透せず、もともと社内でのメッセージのやりとりはIPメッセンジャーを使ってたので
それ以外はだれも使いたがりませんでした。
で、結局社内への導入は失敗し、つまんないの~と思ってて、でも、IRCでの情報共有はいいな~やっておきたいな~と思い、
この地域(私は東京から仙台に引っ越した)にIRC系のサーバーないのかな~と考えるようになりました。
で調べたところ、東北地域にはなかったので、自分で立てることにした。
自分でたてなくても、日本国内には、たくさんのIRCホスト(http://tomocha.net/docs/irc/server_link.html)があるし、海外にもfreenode 
とかがあるから、それらを使えばいーじゃなぃ?というのもあるけど、いろいろ思うところもあり、自分とこにたてる事にした。
で、自分とこにたてるのも、最初は ngIRCd を使っていたんだけど、細かな設定が上手くできなく、POE::Component::Server::IRC の存在も知っていたので、
それならIRCサーバーを作ってしまおうと思ったわけです。
作るといっても、POE::Component::Server::IRC を使うので作るというほどでもないですが、いくつか注意点があったので、それをUPしようと思いました。
 
に、ある、IRCホストirc.arbolbell.jp は、PoCo::Server::IRCを使ってます。ここにある日付からもわかるように、IRCサーバーを立てたのは今年3月はじめなので
今回の記事を書くのに時間がかかってしまいました。
 
本題にもどります。
 
まず、
IRC で SSLでの通信を有効にするために openssl-devel をインストールしときます。
$ sudo yum install openssl-devel

そして、CPANモジュールをインストールです。

cpan> install POE::Component::Server::IRC
cpan> install POE::Component::SSLify


SSL対応にしたいので
use POE::Component::SSLify qw( Server_SSLify SSLify_Options Client_SSLify );
します。


1つめの注意点は、PoCo::Server::IRC Ver 1.38のドキュメントに、SSLでの接続の仕方が書いていないけど、SSL接続に対応していて使えるということ。
私はどこに書いてあるか分からず、SSLでの接続は対応していないかと思いました。
しかし、テストコードを見てみると、しっかりとSSL接続のテストが書いてありました。

POE::Component::Server::IRC でのSSL接続は、
    $heap->{ircd}->add_listener( port => $port_ssl, usessl => 1 );
の様に、add_listenerで、ポートを割り当てる際に usesslフラグを立てることで可能ですが、ドキュメントには書かれていなかったのです。

※add_listenerに関する記述:
add_listener

Takes a number of arguments. Adds a new listener.

        'port', the TCP port to listen on. Default is a random port;
        'auth', enable or disable auth sub-system for this listener. Default enabled;
        'bindaddr', specify a local address to bind the listener to;
        'listenqueue', change the SocketFactory's ListenQueue;

A listener is required to accept connections from clients.



もうひとつ注意が必要なのは、IRCコマンド /info で表示する情報です。
Ver 1.38 では、ソースに記述ミスがあり、いくら設定してもデフォルトの表示しかされません。

その箇所を 修正して diff したのが次のです。

$ diff -u /usr/local/lib/perl5/site_perl/5.10.0/POE/Component/Server/IRC.pm ~/lib/perl/POE/Component/Server/IRC.pm
--- /usr/local/lib/perl5/site_perl/5.10.0/POE/Component/Server/IRC.pm   2009-01-27 22:20:14.000000000 +0900
+++ ~/lib/perl/POE/Component/Server/IRC.pm        2009-03-04 10:21:27.000000000 +0900
@@ -4668,7 +4668,7 @@
     $self->{config}->{ADMIN}->[1] = 'Some Institution';
     $self->{config}->{ADMIN}->[2] = 'someone@somewhere';
   }
-  if ( ( not defined ( $self->{config}->{INFO} ) ) or ( ref $self->{config}->{INFO} eq 'ARRAY' ) or ( scalar ( @{ $self->{config}->{INFO} } ) >= 1 ) ) {
+  if ( ( not defined ( $self->{config}->{INFO} ) ) or ( ref $self->{config}->{INFO} ne 'ARRAY' ) or ( scalar ( @{ $self->{config}->{INFO} } ) == 0 ) ) {
     $self->{config}->{INFO}->[0] = '# POE::Component::Server::IRC';
     $self->{config}->{INFO}->[1] = '#';
     $self->{config}->{INFO}->[2] = '# Author: Chris "BinGOs" Williams';
 
 
で使っている IRCサーバーのソースと設定ファイル

#!/usr/bin/env perl

use strict;
use warnings;
use Data::Dumper;
use YAML;
use Class::Inspector;
use POE qw(Component::Server::IRC);
use POE::Component::SSLify qw( Server_SSLify SSLify_Options Client_SSLify );


# 設定ファイル読み込み
my $yaml = YAML::LoadFile('irc.yaml');

# 通常運用時と、テスト起動時のポート
my ($switch) = @ARGV || ("");
my ($port_nossl, $port_ssl) = $switch =~ /test/i ? @{$yaml->{test_port}} : @{$yaml->{port}} ;

my $pocosi = POE::Component::Server::IRC->spawn( 
	config 			=> $yaml->{config},
	antiflood 		=> $switch =~ /test/i ? 0 : 1,
	debug 			=> $yaml->{debug},
	sslify_options 	=> $yaml->{sslify_options},
);

POE::Session->create(
	package_states => [ main =>  Class::Inspector->methods(__PACKAGE__) ],
    heap => { ircd => $pocosi },
);

$poe_kernel->run();
exit 0;

my @operator;
sub _start {
	my ($kernel,$heap) = @_[KERNEL,HEAP];
	$kernel->sig( HUP  => '_stop' );
	$kernel->sig( INT  => '_stop' );
	$kernel->sig( TERM => '_stop' );
	$kernel->sig( KILL => '_stop' );
	$heap->{ircd}->yield( 'register' );
	$heap->{ircd}->add_auth( mask => '*@*' );
	$heap->{ircd}->add_listener( port => $port_nossl );
	$heap->{ircd}->add_listener( port => $port_ssl, usessl => 1 );
	# オペレーター
	for( @{$yaml->{operator}} ){
		push @operator, $_->{username};
		$heap->{ircd}->add_operator( $_ );
	}
	# 起動時にチャンネルを作成するためのユーザーを作成
	$heap->{ircd}->yield(add_spoofed_nick=>{nick=>'ircd_bot', ircname => 'The IRC Serv Bot'});
	# 起動時に作成しておくチャンネル
	while ( my ($channel, $topic) = each %{$yaml->{channel_list}} ) {
		$heap->{ircd}->yield(daemon_cmd_join =>'ircd_bot',$channel);
		$heap->{ircd}->yield(daemon_cmd_topic=>'ircd_bot',$channel, $topic);
	}
	undef;
}


sub ircd_daemon_join {
    my $kernel  = $_[KERNEL];
    my $heap    = $_[HEAP];
    my $session = $_[SESSION];
	my ($full_user, $channel) = @_[ARG0, ARG1];
	# オペレーター
	for my $username( @operator ){
		if($full_user =~ /^$username!~$username/ and $heap->{ircd}->state_user_is_operator($username)){
			$heap->{ircd}->yield(daemon_cmd_mode=>'ircd_bot',$channel,'+o',$username);
			last;
		}
	}
}

sub _stop {
    my $heap    = $_[HEAP];
	$heap->{ircd}->yield( 'shutdown' );
	delete $heap->{ircd};
}

sub _default {
 my ( $event, $args ) = @_[ ARG0 .. $#_ ];
 print STDOUT "$event: ";
 foreach (@$args) {
 SWITCH: {
          if ( ref($_) eq 'ARRAY' ) {
              print STDOUT "[", join ( ", ", @$_ ), "] ";
              last SWITCH;
          }
          if ( ref($_) eq 'HASH' ) {
              print STDOUT "{", join ( ", ", %$_ ), "} ";
              last SWITCH;
          }
          print STDOUT "'$_' ";
      }
  }
  print STDOUT "\n";
  return 0;    # Don't handle signals.
}


 

$ cat irc.yaml
---
channel_list:
  '#lounge': ラウンジ. http://arbolbell.jp/irc
  '#test': テスト用. http://arbolbell.jp/irc
config:
  admin:
    - irc.arbolbell.jp
    - http://arbolbell.jp/irc
    - suzu@mail.*****.jp
  info:
    - '******************'
    - http://arbolbell.jp/irc
    - '******************'
  motd:
    - ''
    - ''
    - ''
    - ''
    - '    ----------------------------------------------------------------------'
    - '    The character code of this host is UTF-8.'
    - '    ----------------------------------------------------------------------'
    - ''
    - '    ようこそ irc.arbolbell.jp へ'
    - ''
    - '    ※実験的に立ち上げているサーバのため、予告無く再起動、停止等が行われる'
    - '      場合があります。あしからず御了承ください。'
    - '    ※全ては無保証で一切責任を負いませんので自己責任でご利用下さい。'
    - ''
    - '    このIRCサーバーはSSLに対応しています。'
    - '    SSL対応のクライアントをご利用の場合、SSLで接続可能です。'
    - ''
    - '    SSL接続  ポート番号:6668 '
    - '    非SSL接続ポート番号:6667'
    - ''
    - '    このIRCホストに関しては、http://arbolbell.jp/irc を参照してください。'
    - ''
    - '    ★次のチャンネルは、サーバー起動時に作られます。'
    - '      #lounge  ・・・・ラウンジです。'
    - '      #test    ・・・・テスト用です。'
    - ''
    - '    ★チャンネル作成のガイドライン '
    - '     ・チャンネル名は、わかりやすい名前を付けてください。 '
    - '     ・topic も、わかりやすくおねがいします。'
    - '     ・topic は必ず設定してください。'
    - ''
    - '    ----------------------------------------------------------------------'
  network: arbolbell.jp
  nicklen: 15
  serverdesc: http://arbolbell.jp/irc
  servername: irc.arbolbell.jp
  version: irc.arbolbell.jp 0.01
debug: 1
operator:
  - ipmask: '*'
    password: mypass1
    username: suzuk1
  - ipmask: '*'
    password: mypass2
    username: suzuk2
port:
  - 6667
  - 6668
sslify_options:
  - ./server-key.pem
  - ./server-cert.pem
test_port:
  - 16667
  - 16668

 

トラックバック(0)

トラックバックURL: http://arbolbell.jp/mt5/mt-tb.cgi/152

コメントする

このブログ記事について

このページは、Yuji Suzukiが2009年5月26日 00:08に書いたブログ記事です。

ひとつ前のブログ記事は「Redmine のユーザーと、SVNのユーザーを同期させる。」です。

次のブログ記事は「IRCにメッセージを流す中継を行うIRCbot (POEIKC::Plugin::IRC)」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。