@matsumotory さん謹製の mod_mruby と mruby-geoip で地理情報を使ってアクセス制御してみた。

スペック

1
2
3
4
5
# more /etc/redhat-release
CentOS Linux release 7.1.1503 (Core)

# uname -r
3.10.0-229.7.2.el7.x86_64

apacheをインストール

1
yum -y install httpd httpd-devel

必要パッケージをインストール

1
yum -y install git vim-enhanced ruby gcc GeoIP-devel GeoIP-update

パッケージの説明をかるく書いておく。

Package Description
git mod_mrubyをgitリポジトリから取得するため
vim-enhanced なくてもよい
ruby mod_mruby入れるのに必要
gcc mod_mrubyコンパイルするために必要
GeoIP-devel mruby-geoipコンパイルするために必要
GeoIP-update GeoIPデータベースのアップデートするツール

mod_mrubyをcloneする。

1
git clone git://github.com/matsumoto-r/mod_mruby.git

build_config.rbを修正

今回は、mruby-geoip を導入したので、入れた。さらにredis,vedisは使わないのでコメントに。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# diff -ur build_config.rb_backup build_config.rb
--- build_config.rb_backup 2015-07-03 13:32:27.017667686 +0900
+++ build_config.rb 2015-07-03 13:37:33.756710824 +0900
@@ -15,13 +15,14 @@
conf.gem :github => 'iij/mruby-pack'
conf.gem :github => 'mattn/mruby-json'
conf.gem :github => 'mattn/mruby-onig-regexp'
- conf.gem :github => 'matsumoto-r/mruby-redis'
- conf.gem :github => 'matsumoto-r/mruby-vedis'
+ #conf.gem :github => 'matsumoto-r/mruby-redis'
+ #conf.gem :github => 'matsumoto-r/mruby-vedis'
conf.gem :github => 'matsumoto-r/mruby-sleep'
conf.gem :github => 'matsumoto-r/mruby-userdata'
conf.gem :github => 'matsumoto-r/mruby-uname'
conf.gem :github => 'matsumoto-r/mruby-cache'
conf.gem :github => 'matsumoto-r/mruby-mutex'
+ conf.gem :github => 'matsumoto-r/mruby-geoip'

# mod_mruby extended class
conf.gem '../mrbgems/mod_mruby_mrblib'

ビルドしよう!

1
sh build.sh

正常にビルドが終わると、以下のように successful と表示される。

1
*** Warning: Linking the shared library src/mod_mruby.la against the
*** static library ./mruby/build/host/lib/libmruby.a is not portable!
mod_mruby building ... Done
build.sh ... successful

apacheに組み込む。

1
make install

実行結果はこちら

1
2
3
4
5
6
7
8
9
# make install
/usr/bin/apxs -i -a -n 'mruby' /home/atani/mod_mruby/src/.libs/mod_mruby.so
/usr/lib64/httpd/build/instdso.sh SH_LIBTOOL='/usr/lib64/apr-1/build/libtool' /home/atani/mod_mruby/src/.libs/mod_mruby.so /usr/lib64/httpd/modules
/usr/lib64/apr-1/build/libtool --mode=install install /home/atani/mod_mruby/src/.libs/mod_mruby.so /usr/lib64/httpd/modules/
libtool: install: install /home/atani/mod_mruby/src/.libs/mod_mruby.so /usr/lib64/httpd/modules/mod_mruby.so
Warning! dlname not found in /usr/lib64/httpd/modules/mod_mruby.so.
Assuming installing a .so rather than a libtool archive.
chmod 755 /usr/lib64/httpd/modules/mod_mruby.so
[activating module `mruby' in /etc/httpd/conf/httpd.conf]

GeoIPのデータベースを取得する。

初期のGeoIPデータは古いので、geoipupdate で最新のデータを取得する。

1
2
3
4
5
6
7
8
9
10
11
12
 ll /usr/share/GeoIP/
total 17696
lrwxrwxrwx. 1 root root 17 Jul 3 13:56 GeoIP.dat -> GeoIP-initial.dat
-rw-r--r--. 1 root root 1362244 Jun 10 2014 GeoIP-initial.dat

# geoipupdate
/usr/share/GeoIP/GeoLiteCountry.dat can't be opened, proceeding to download database
Updating /usr/share/GeoIP/GeoLiteCountry.dat
Updated database
/usr/share/GeoIP/GeoLiteCity.dat can't be opened, proceeding to download database

Updating /usr/share/GeoIP/GeoLiteCity.dat
Updated database

mruby-geoipの設定

ここからはmruby-geoipを利用するための設定をしよう。

1
mkdir /etc/httpd/hook

httpd.conf

1
2
3
4
5
mrubyChildInitMiddle /etc/httpd/conf.d/geo_init.rb
<Location />
mrubyAccessCheckerLast /etc/httpd/conf.d/geo_check.rb
mrubyHandlerMiddle /etc/httpd/conf.d/geo_handler.rb
</Location>

geo_check.rbmrubyAccessCheckerMiddle で処理させようとすると地理情報の値がうまく値が取れなかった。

/etc/httpd/conf.d/geo_init.rb

1
Userdata.new("geoip_#{Process.pid}").geoip = GeoIP.new("/usr/share/GeoIP/GeoLiteCity.dat")

/etc/httpd/conf.d/geo_check.rb

1
2
3
4
5
6
7
8
Server = get_server_class

geoip = Userdata.new("geoip_#{Process.pid}").geoip
geoip.record_by_addr Server::Connection.new.remote_ip

if geoip.country_code != "JP"
Server.return Server::HTTP_FORBIDDEN
end

/etc/httpd/conf.d/geo_handler.rb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Server = get_server_class

r = Server::Request.new
c = Server::Connection.new
geoip = Userdata.new("geoip_#{Process.pid}").geoip

r.content_type = "text/html"
Server.echo "<HEAD><TITLE>your information</TITLE></HEAD><BODY>"
Server.echo "Your IP Address is #{c.remote_ip}<br>"
Server.echo "Your Country Code is #{geoip.country_code}<br>"
Server.echo "Your city is #{geoip.city}<br>"
Server.echo "Your region is #{geoip.region}<br>"
Server.echo "your are at <a href='http://maps.google.com/maps?q=#{geoip.latitude},#{geoip.longitude}'>this pin</a><br>"
Server.echo "</BODY>"

apacheを起動

  • configtestを行い、問題なければ起動。

    1
    2
    3
    # /usr/sbin/apachectl configtest
    Syntax OK
    # /usr/sbin/apachectl start
  • systemdで起動する場合は、httpdにUNIT登録したあと、起動する。

    1
    2
    3
    # systemctl enable httpd.service
    ln -s '/usr/lib/systemd/system/httpd.service' '/etc/systemd/system/multi-user.target.wants/httpd.service'
    # systemctl start httpd.service

実際にアクセスしてみると国コードなど取得できることを確認!

[access.png]

JP(日本) 以外からアクセスした場合は403エラー

[error.png]

備考

gcc が入ってないと以下のようなエラーとなる。

1
Command Failed: [gcc -g -std=gnu99 -O3 -Wall -Werror-implicit-function-declaration -Wdeclaration-after-statement -Wwrite-strings -fPIC -g3 -Wall -Werror-implicit-function-declaration -I"/home/atani/mod_mruby/mruby/include" -MMD -o "/home/atani/mod_mruby/mruby/build/host/src/array.o" -c "/home/atani/mod_mruby/mruby/src/array.c"]

bison が入ってないと以下のようなエラーとなる。

1
2
3
4
sh: bison: command not found
sh: bison: command not found
rake aborted!
Command Failed: [bison -o "/home/atani/mod_mruby/mruby/build/host/mrbgems/mruby-compiler/core/y.tab.c" "/home/atani/mod_mruby/mruby/mrbgems/mruby-compiler/core/parse.y"]

openssl-devel が入ってないと以下のようなエラーとなる。

1
2
3
4
5
6
7
8
9
10
/home/atani/mod_mruby/mruby/build/mrbgems/mruby-digest/src/digest.c:16:25: fatal error: openssl/evp.h: No such file or directory
#include <openssl/evp.h>
^
compilation terminated.
/home/atani/mod_mruby/mruby/build/mrbgems/mruby-digest/src/digest.c:16:25: fatal error: openssl/evp.h: No such file or directory
#include <openssl/evp.h>
^
compilation terminated.
rake aborted!
Command Failed: [gcc -g -std=gnu99 -O3 -Wall -Werror-implicit-function-declaration -Wdeclaration-after-statement -Wwrite-strings -fPIC -g3 -Wall -Werror-implicit-function-declaration -DMRBGEM_MRUBY_DIGEST_VERSION=0.0.0 -I"/home/atani/mod_mruby/mruby/include" -MMD -o "/home/atani/mod_mruby/mruby/build/host/mrbgems/mruby-digest/src/digest.o" -c "/home/atani/mod_mruby/mruby/build/mrbgems/mruby-digest/src/digest.c"]

GeoIP-devel が入ってないと以下のようなエラーとなる。

1
2
3
4
5
6
7
8
9
10
/home/atani/mod_mruby/mruby/build/mrbgems/mruby-geoip/src/mrb_geoip.c:12:19: fatal error: GeoIP.h: No such file or directory
#include <GeoIP.h>
^
compilation terminated.
/home/atani/mod_mruby/mruby/build/mrbgems/mruby-geoip/src/mrb_geoip.c:12:19: fatal error: GeoIP.h: No such file or directory
#include <GeoIP.h>
^
compilation terminated.
rake aborted!
Command Failed: [gcc -g -std=gnu99 -O3 -Wall -Werror-implicit-function-declaration -Wdeclaration-after-statement -Wwrite-strings -fPIC -g3 -Wall -Werror-implicit-function-declaration -DMRBGEM_MRUBY_GEOIP_VERSION=0.0.1 -I"/home/atani/mod_mruby/mruby/include" -MMD -o "/home/atani/mod_mruby/mruby/build/host/mrbgems/mruby-geoip/src/mrb_geoip.o" -c "/home/atani/mod_mruby/mruby/build/mrbgems/mruby-geoip/src/mrb_geoip.c"]

httpd-devel が入ってないと以下のようなエラーとなる。

1
2
3
4
5
6
7
8
--with-mruby: https://github.com/mruby/mruby.git will be used.
checking for rake1.9.1... no
checking for rake... no
checking for ruby1.9.1... no
checking for ruby... /usr/bin/ruby
checking for apxs2... no
checking for apxs... no
configure: error: neither apxs2 or apxs not found.

参照URL