Eximのlocal_scan動的読込み機能 その3
前回は本当にさわりだけだったので、今回は実際に役に立つ機能を加えたいと思います。実際にどんな機能を実装しようかと考えたのですが、以前qmailでMTAを運用しているときに独自に追加したGeoIP関連の処理を追加することにしました。
GeoIPとは
GeoIPはMaxMind社が提供しているサービス及びデータベースの事で、IPアドレスから国や地域を調べることが出来ます。基本有料のサービスなのですが、精度が少し低くて更新が自動で出来ないバージョンは無料で利用出来ますので、今回はこれを利用します。
GeoIPデータベースを使うと国や地域だけでなく都市名なども分かるのですが、今回は国名と座標をメールヘッダーに追加します。
GeoIPライブラリのインストール
GeoIPを利用するためにまずライブラリのインストールを行います。MaxMindの開発者向けページを見るとGeoIP2というのも出てきていますが、これから実装する機能にはLegacy版で十分ですので、Debianにあるパッケージを使ってちゃっちゃとインストールします。他のディストリビューションやOSをお使いの方は先ほどのページを参考に頑張って下さい。
sudo apt-get install libgeoip1
sudo apt-get install libgeoip-dev
sudo apt-get install geoip-database
wget http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip GeoLiteCity.dat.gz
sudo mv GeoLiteCity.dat /usr/share/GeoIP
これで開発の準備は完了です。
local_scanの作成(geoip-exim.c)
さっそくソースコード見て下さい。前回の説明した最小限の構成と比べるとlocal_scan関数に少しばかりコードが増えていますが、やっていることは簡単で以下のような事を行っています。
- データベースをオープン
- メール送信者のIPアドレスを元にデータベースを検索
- 検索結果を元にX-Geoip-CountryとX-Geoip-Coordinatesヘッダーを追加
- 検索結果の後始末
- データベースをクローズ
#include <local_scan.h>
#include <GeoIP.h>
#include <GeoIPCity.h>
#define MAX_LENGTH 998
static const char *_mk_NA(const char *p)
{
return p ? p : "N/A";
}
int local_scan_version_major(void)
{
eturn LOCAL_SCAN_ABI_VERSION_MAJOR;
}
int local_scan_version_minor(void)
{
return LOCAL_SCAN_ABI_VERSION_MINOR;
}
int local_scan(int fd, uschar **return_text)
{
fd = fd;
return_text = return_text;
/* open geoip database */
GeoIP *gi;
GeoIPRecord *gir;
char header[MAX_LENGTH];
gi = GeoIP_open("/usr/share/GeoIP/GeoLiteCity.dat", GEOIP_MEMORY_CACHE);
if (gi == NULL) return LOCAL_SCAN_ACCEPT;
gir = GeoIP_record_by_addr(gi, (const char*)sender_host_address);
if (gir == NULL) {
GeoIP_delete(gi);
return LOCAL_SCAN_ACCEPT;
}
snprintf(header, MAX_LENGTH, "X-Geoip-Country: %s\n", _mk_NA(gir->country_code));
header_add((int)' ', header);
snprintf(header, MAX_LENGTH, "X-Geoip-Coordinates: %f/%f\n", gir->latitude, gir->longitude);
header_add((int)' ', header);
GeoIPRecord_delete(gir);
GeoIP_delete(gi);
return LOCAL_SCAN_ACCEPT;
}
コンパイルして配置します。
gcc -Wall -I/usr/include -I/usr/include/exim4 -Wl,-R/usr/share/GeoIP -fPIC -c geoip-exim.c
gcc -shared -export-dynamic -ldl -Wl,-soname,libGeoIPExim.so.1 -olibGeoIPExim.so.1.0 geoip-exim.o -L/usr/lib -lGeoIP
sudo cp libGeoIPExim.so.1.0 /usr/lib/exim4/local_scan/
cd /usr/lib/exim4/local_scan/
sudo ln -s libGeoIPExim.so.1.0 libGeoIPExim.so
Eximに設定を追加して再起動します。
local_scan_path = /usr/lib/exim4/local_sacn/libGeoIPExim.so
届いたメールにX-Geoip-*
から始まるヘッダーが二つ追加されていれば問題無く動作しています。local_scanがクラッシュしてもExim本体側で絵エラーハンドリングされるはずですが、テストもしないでいきなり本番サーバーで実行したりなど無謀な事はしないで下さい。何が起こっても当局は一切関知しません。