2011年4月29日金曜日

ruby 1.9.*でURL短縮サービスを作る

rubyでは、URL短縮サービスをWebサーバごと、しかも簡単に作ってしまうことができる。 その上、必要なライブラリはruby1.9.*標準添付ライブラリのみ。

ここでは、以下の機能を実装してみる。
  • /regのクエリにURLを渡しGETすると、元のURLとJSONで短縮したURLを返す
  • 短縮したURLはgdbmのデータベースに保存し、サーバ再起動後も参照できるものにする
  • 短縮にはMD5ハッシュを用いる(このままでは長いがとりあえず)

ソースコードは以下のとおり。
#!/usr/bin/env ruby1.9.2
#-*- coding: utf-8 -*-

require 'webrick'
require 'uri'
require 'gdbm'
require 'json'
require 'digest/md5'

# このサーバのURLを指定
BASE_URL = 'http://localhost:3939/'
# 短縮URLのデータベースファイル
db = GDBM.new('url.db')

# Webサーバを作成
sv = WEBrick::HTTPServer.new(:Port => URI.parse(BASE_URL).port)
trap(:INT){sv.stop}

# 短縮されたURLを受け取り、転送するServletを/にmount
sv.mount_proc('/'){|req, res|
  digest = req.path.gsub(/^\//, '')
  if digest =~ /^[0-9a-z]+$/i &&
      url = db[digest]
    res.set_redirect(WEBrick::HTTPStatus::Found, url)
  else
    res.body = 'unknown digest'
  end
}

# URLを短縮してJSONで返すServletを/regにmount
sv.mount_proc('/reg'){|req, res|
  url    = req.query['url']
  if url =~ URI.regexp && 
      URI.parse(url).scheme =~ /^(https?|ftp)$/
    digest = Digest::MD5.hexdigest(url)
    db[digest] = url
    res.body   = JSON.dump({'digest'=> digest,
                             'turl' => BASE_URL + digest,
                             'url'  => url})
  else
    res.body = 'bad url'
  end
}

# サーバを開始
sv.start
これだけでOK。
http://localhost:3939/add?url=http://hachune.net/http://hachune.net/を短縮URLサービスに登録し、返されたhttp://localhost:3939/fd9f9871bca66e8b49a919138982c9c1にアクセスすると、http://hachune.net/に転送される。
Apacheの用意も新規ライブラリの導入も要らず、とってもお手軽。
あとは、MD5のままだとどう見ても長すぎるので、可能な限り衝突が起きにくくかつ文字列の長さが短くなる関数を作る必要があるが、まぁその辺は適当に。

2011年4月21日木曜日

OpenBSDで6to4なIPv6ルータを作る

IPv4アドレスがついに枯渇! …ということで、自宅のOpenBSD/macppcなルータでIPv6接続ができるようにしてみた。 今回は、固定IPv4アドレスが既にあるので、6to4を用いてグローバルIPv6アドレスを設定する。

固定IPv4アドレスを割り当て

最初に、IPv4アドレスをルータに割り当てる。 いつも通り、/etc/hostname.pppoe0に設定を書く。 当然ながら、ユーザ名とパスワードは自分の契約しているプロバイダのものに置き換える。 ここで用いられるインターフェースは、gem0がWAN側ネットワークに接続されている物理インターフェース、 pppoe0がPPPoE接続で用いられるインターフェースである。
# /etc/hostname.pppoe0

inet 0.0.0.0 255.255.255.255 NONE \
pppoedev gem0 authproto chap \
authname 'username' authkey 'passwd' up
dest 0.0.0.1
!/sbin/route add default -ifp pppoe0 0.0.0.1

6to4のトンネルを作成

次に、6to4のトンネルインターフェースを設定する。 OpenBSDのトンネルインターフェースはgifであるので、/etc/hostname.gif0に設定を記入する。
6to4トンネルの宛先は、192.88.99.1で固定の模様。

6to4では、「2002:IPv4アドレスを16進表記したもの::/48」を、 このルータのIPv6ネットワークとして利用することができる。 このルータのグローバルIPv4アドレスは、180.131.124.186なので、 2002:b483:7cba::/48がそれに当たる。
10進→16進変換は、printfコマンドでprintf "%x %x %x %x\n" 180 131 124 186のようにすれば簡単。
# /etc/hostname.gif0

up giftunnel 180.131.124.186 192.88.99.1
inet6 2002:b483:7cba::1 64
!route add -inet6 default 2002:b483:7cba::1

IPv6フォワーディングを有効化

このルータだけがIPv6アドレスを持っていてもあまり面白くないので、 IPv4同様、IPv6フォワーディングを有効化する。 /etc/sysctl.confの以下の部分のコメントアウトを外すだけでOK。
# /etc/sysctl.conf

net.inet6.ip6.forwarding=1

内部インターフェースへのIPv6アドレスの割り当て

内部ネットワークを2002:b483:7cba:39::/64とし、 内部向けインターフェースaxe0に、2002:b483:7cba:39::1を割り当てる。
# /etc/hostname.axe0

inet alias 10.39.39.1 255.255.255.0
inet6      2002:b483:7cba:39::1 64

router advertisement daemonを有効化

IPv6では、DHCPを用いずに動的にIPv6アドレスを割り当てることができる。 OpenBSDでは、rtadvdにより自動割当を行う。 有効化の設定は、/etc/rc.conf.localに、rtadvd_flagsを追加し、 引数に自動割当を行うインターフェース名を記入する。
このrtadvdにより、axe0以下のIPv6対応コンピュータには、axe0のネットワーク 2002:b483:7cba:39::/64の中から自動的にアドレスが割り当てられる。
# /etc/rc.conf.local

rtadvd_flags="axe0"

pfにIPv6のルールを追加

IPv6でも当然ながらフィルタリングは必要なので、pfを設定する。 最低限許可が必要なのは、6to4トンネルのパケットと、自動割り当てに必要なパケットである。 これ以外は必要に応じて追加する。
# /etc/pf.conf

# Pass 6to4 tunnel
pass  out on $ext_if proto ipv6 \
      from pppoe0 to 192.88.99.1
block in log (all) inet6

# Pass Router Solicitations (RS)
pass in  log (all) on axe0 \
     inet6 proto icmp6 \
     icmp6-type routersol

# Pass Router Advertisement (RA)
pass out log (all) on axe0 \
     inet6 proto icmp6 \
     icmp6-type routeradv
正しくグローバルIPv6アドレスが割り当てられているか確認したいときは、ping6 ipv6.google.comするなりlynxで開くなりなんなりと。

debianやubuntuでmikutterビルド環境を作る

あまりに何度もmikutterビルド環境を構築しているので、そろそろ纏めてみる。

ベースシステムを構築

/var/rootにビルド用のubuntu nattyをdebootstrapにて用意する。 この中で全ての作業を行うことになるので、バグがあったり操作ミスしたりしてもシステム全体に被害は及びにくくなる。また、それぞれ違うディストリビューションやバージョンを用いることもできる(debian sidやubuntu lucidなど)。
ホストがamd64な環境ならば、debootstrapにオプション--arch i386を追加することで、i386な環境を構築することも可能。
# aptitude install debootstrap
# mkdir /var/root
# cd /var/root
# debootstrap natty ./natty

基本システムをmikutterビルド用にセットアップ

新たに作ったubuntu nattyの中にchrootする。 chroot後は、必要なファイルやパッケージを、通常のシステム同様にapt等を用いて準備する。
# chroot /var/root/natty /bin/bash
# apt-get update
# apt-get install \
gcc make  pkg-config subversion libnotify-bin wget \
libgtk2.0-dev libsqlite3-dev libssl-dev zlib1g-dev
もしsysやprocが見つけられないことが原因でエラーになるようであれば、 chrootから一度抜けだしてマウントしておく。
必要以上にマウントすると、なんらかのミスでとんでもないことになる可能性もあるので注意。
# mount -t proc proc ./natty/proc
# mount -o bind /dev ./natty/dev
# mount -t devpts devpts ./natty/dev/pts
# mount -t sysfs sysfs ./natty/sys

Rubyをビルド

そしてchroot内でruby1.9.2をビルドし、必要なrubyパッケージをgemで追加する。
# cd /usr/src
# wget ftp://ftp.ruby-lang.org/pub/ruby/ruby-1.9.2-p180.tar.gz
# tar xzf ruby-1.9.2-p180.tar.gz
# cd ruby-1.9.2-p180
# ./configure --prefix=/usr/ruby192 --program-suffix=192
# make && make install
# /usr/ruby192/bin/gem192 install ruby-hmac gtk2 sqlite3

mikutterをcheckout

最後にmikutterをcheckoutすれば、mikutterビルド環境のできあがり。
# cd /usr/src
# svn co svn://mikutter.hachune.net/mikutter/trunk/ mikutter
あとはsshのX転送やvnc等などを利用して、mikutterが動くかどうか試す。
おそらく日本語がまともに表示されずガッカリすることになるので、
# apt-get install ttf-vlgothic
などとしておくとよいかもしれない。

2011年4月20日水曜日

心機一転

数年間書き続けていたBlogの整理がそろそろつかなくなったので、新しく作りなおしてみることにする。 hachune.*のサーバ構築や管理、プログラミング関係の話題が多くなりそうな予感。