One of the main reasons that I visited Seoul in January 2011 – “Bukchon Hanok Village”

The Accidental Couple” is one of my favorite Korean TV dramas, and “Bukchon Hanok Village” is the location for the TV darama where many key scenes were taken. That’s why I had thought about going to “Bukchon Hanok Village”, and finally I did it in January 2011. See the following pictures and compare.

The first one is the one I captured on TV screen while playing the daram(the HDD recorded).
The Scene of  the Accidental Couple

The other one is the one I actually took in Bukchon Hanok Village, Seoul. There are building improvements going on around there, so it may look a little bit different from the one above. But it’s the same location!
P1070710

Well, apart from the location for the TV drama, “Bukchon Hanok Village” is a famous Korean village in Seoul where Korean traditional houses which is called hanok have been preserved. There are lots of tourist spots and fancy cafes etc around there . It is good to go visit there even if you don’t have passion for it like me. I bet you’d like it.

See also:

Posted in: Random Topics

Tags: ,

How to setup Wikileaks mirror site by using wget and Github


Wikileaks mirror site on github.com

Wikileaks, a new internet media NPO launched its website in 2006,has been under threat of being eliminated from the internet. Wikileaks lost its DNS service and its main domain(wikileaks.org) has not been reachable due to heavy DDoS Attacks on Wikileaks. Some large U.S companies such as Bank of America, Amazon, Paypal have already stopped giving service to Wikileaks. There are many organization/people who don’t support Wikileaks and who are desperate to shut down Wikileaks’ website, to speak of extremes. Wikileaks is not just one website. Good or bad, it is a lot more powerful and influential than you’ve ever thought.

There are millions of Wikileaks supporters all over the world. You will be surprised to see how many of mirror sites has been setup. Wikileaks has been seeking support and it currently has 1426 mirrors registered at this time (Dec24,2010) if my counting is not wrong. Of course, you also can be one of the Wikileaks supporters by hosting a mirror of the site. Wikileaks provides simple instructions on how to setup a WikiLeaks mirror on its Mass-mirroring Wikileaks page. Basically you need to have a unix based server on which web server is running first, then give Wikileaks staff access permission to the server so that they can upload a copy of the Wikileaks site. That’s how you provide the the Wikileaks content from your webserver. But don’t you think it is risky to host the Wikileaks content on your server? Highly possibly your server may suffer from DDoS Attacks. What if whoever attackers get to know who you are from your domain registration record or something? it may be frightening … Soooooo here I am going to introduce the way you can set up a Wikileaks mirror site without having such a risk of your expose to the attackers and without having any hosting space for Wikileaks.  — Here I use wget and github on linux environment (ubuntu).

Github as web server

What you need to do is basically only 2 steps:

  • 1. mirror a Website with all markup, text, css, scripts, images, etc. to your local machine
  • 2. save the content to the github repository(project name: username.github.com).

Then, the Github Pages allows you to publish the content to the web as if you publish the content on your own site. The Github Pages rule is very simple. If your Github username is ‘wikileaks-mirror-jp’ and you push the content to repository named ‘wikileaks-mirror-jp.github.com’, the content can be accessible through the URL – http://wikileaks-mirror-jp.github.com. In short, you can use Github as web server to publish the mirriroed wikileaks content to the web.

1. Setup a Github user account for the mirror

You need to setup a Github user account so that you can push the content to Github repositories. Let’s say your Github username is ‘wikileaks-mirror-jp’ and you have an existing unix user named ‘wikileaks-mirror-jp’ on your linux machine. Firest of all, you need to add wikileaks-mirror-jp’s SSH pub key to the Github account. This below is how I created SSH pub key, id_rsa_github.pub. See also Generating SSH keys for more detail.

$ su wikileaks-mirror-jp
$ ssh-keygen -t rsa

Generating public/private rsa key pair.
Enter file in which to save the key (/home/wikileaks-mirror-jp/.ssh/id_rsa): /home/wikileaks-mirror-jp/.ssh/id_rsa_github
Created directory '/home/wikileaks-mirror-jp/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/wikileaks-mirror-jp/.ssh/id_rsa_github.
Your public key has been saved in /home/wikileaks-mirror-jp/.ssh/id_rsa_github.pub.
The key fingerprint is:
92:23:42:9e:70:c8:ef:65:68:d5:23:0d:62:af:da:87 wikileaks-mirror-jp@ubuntu
The key's randomart image is:
....

Then, configure SSH like this below so as for the SSH key created above to be used in accessing to github.com server through SSH. See also Multiple SSH Keys for more detail.

$ vi ~/.ssh/config

Host github.com
  User wikileaks-mirror-jp
  Port 22
  Hostname github.com
  IdentityFile ~/.ssh/id_rsa_github
  TCPKeepAlive yes
  IdentitiesOnly yes

Finally, add the SSH pub key on your account setting page.

2. Create a Github repository for the mirror

Once the Github account is ready, then you need to create a new repository for Github user page , wikileaks-mirror-jp.github.com. First, you need to create a new reposotiry by entering project name, description and homepage URL on Create a New Repository page. The new project Name is wikileaks-mirror-jp.github.com

Then, you create an empty git repository for wikileaks-mirror-jp.github.com and add a sample file to the repository like this below.

$ git config --global user.name "wikileaks-mirror-jp"
$ mkdir ~/github
$ mkdir wikileaks-mirror-jp.github.com
$ cd wikileaks-mirror-jp.github.com
$ git init
$ touch README
$ echo "wikileaks-mirror-jp.github.com" > README
$ git add README
$ git commit -m 'first commit'
$ git remote add origin git@github.com:wikileaks-mirror-jp/wikileaks-mirror-jp.github.com.git
$ git push origin master

You will see the sample file pushed to the repository on the project page.

3. Wikileaks mirroring with wget

Here you mirror a Wikileaks website to your local machine by using a wget command. Let’s say the mirroring target site is http://wikileaks.ch and you save all the files and subdiectories to the directory where create the empty git repository for wikileaks-mirror-jp.github.com, ~/github/wikileaks-mirror-jp.github.com. By executing the following command line, you will have all the files downloaded from http://wikileaks.ch under the directory for the Github repository.

$ wget --mirror --convert-links -w 2 -p -e robots=off \
         -P ~/github/wikileaks-mirror-jp.github.com http://wikileaks.ch/

--2010-12-23 22:39:40--  http://wikileaks.ch/
Resolving wikileaks.ch... 178.21.20.9, 213.251.145.96, 46.59.1.2, ...
Connecting to wikileaks.ch|178.21.20.9|:80... connected.
HTTP request sent, awaiting response... 200 OK
....

Speaking of ‘-e robots=off‘, you need to turn robots param off in order to download some script or css file that are located under the directories which the site’s robots.txt instructs web robots not to visit. Other key options are ‘–mirror‘, ‘–convert-links‘. Please see wget man page or GNU manual for the wget option details.

4. Push the content to the repository to publish to the web

Finally, push the downloaded content to the repository like this below.

$ cd ~/github/wikileaks-mirror-jp.github.com
$ git add *
$ git commit -m "added mirror site"
$ git push

Counting objects: 3043, done.
Compressing objects: 100% (3013/3013), done.
Writing objects: 100% (3042/3042), 20.37 MiB | 39 KiB/s, done.
Total 3042 (delta 2836), reused 0 (delta 0)
To git@github.com:wikileaks-mirror-jp/wikileaks-mirror-jp.github.com.git
   aff2b93..1032dc2  master -> master

Now the content is accessible through http://wikileaks-mirror-jp.github.com. What’s more, if you want to automate the series of commands that you have executed above, put them on crontab. That’s it!

Posted in: Environment Setup

Tags: , , ,

Segmentation fault(11) – Apache2 and libphp5.so on Ubuntu

Ubuntu10.04.1LTSでApache2、PHP5.3がうまく動いてくれない。 同一バージョンのApache、PHPを依存ライブラリをほぼ同じにしてdebian Lennyで試してみると問題なく動作する。 どうにもこうにもならないので後々のためにとりあえず記録だけ残しておく。

1. PROBLEM: Apache2 Segmentation fault(11)

[Sun Nov 28 17:42:48 2010] [notice] Apache/2.2.2 (Unix) PHP/5.3.3 configured -- resuming normal operations
[Sun Nov 28 17:42:48 2010] [notice] child pid 13032 exit signal Segmentation fault (11)
[Sun Nov 28 17:42:49 2010] [notice] child pid 13033 exit signal Segmentation fault (11)
[Sun Nov 28 17:42:52 2010] [notice] child pid 13034 exit signal Segmentation fault (11)
[Sun Nov 28 17:42:56 2010] [notice] child pid 13035 exit signal Segmentation fault (11)

2. Environments

Installations: apache-2.2.2

tar zxf httpd-2.2.2.tar.gz
cd httpd-2.2.2

CC="gcc" OPTIM="-O2" \
 ./configure \
 --prefix=/home/apache-2.2.2 \
 --with-layout=Apache \
 --enable-rewrite \
 --disable-userdir \
 --enable-auth_dbm \
 --enable-usertrack \
 --enable-=so \
 --enable-proxy \
 --enable-proxy-http \
 --enable-proxy-connect \
 --enable-speling \
 --enable-headers \
 --enable-expires \
 --enable-setenvif \
 --enable-cache \
 --enable-disk-cache \
 --enable-mem-cache \
 --enable-info \
 --enable-rule=SHARED_CORE \
 --verbose

make
sudo make install
sudo ln -s /home/apache-2.2.2 /home/apache

Installations: PHP-5.3.3

tar zxvf php-5.3.3.tar.gz
cd php-5.3.3
./configure \
    --with-apxs2=/home/apache/bin/apxs \
    --with-mysql=/home/mysql \
    --with-curl=/usr/lib \
    --with-zlib \
    --enable-mbstring \
    --enable-mbregex \

make
sudo make install

Linux distribution Info

$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 10.04.1 LTS
Release:        10.04
Codename:       lucid

Apache Info

$ /home/apache/bin/apachectl -V

Server version: Apache/2.2.2
Server built:   Apr  4 2010 10:26:51
Server's Module Magic Number: 20051115:2
Server loaded:  APR 1.2.7, APR-Util 1.2.7
Compiled using: APR 1.2.7, APR-Util 1.2.7
Architecture:   32-bit
Server MPM:     Prefork
  threaded:     no
    forked:     yes (variable process count)
Server compiled with....
 -D APACHE_MPM_DIR="server/mpm/prefork"     <--- サーバは MPM/Prefork
 -D APR_HAS_SENDFILE
 -D APR_HAS_MMAP
 -D APR_HAVE_IPV6 (IPv4-mapped addresses enabled)
 -D APR_USE_SYSVSEM_SERIALIZE
 -D APR_USE_PTHREAD_SERIALIZE
 -D SINGLE_LISTEN_UNSERIALIZED_ACCEPT
 -D APR_HAS_OTHER_CHILD
 -D AP_HAVE_RELIABLE_PIPED_LOGS
 -D DYNAMIC_MODULE_LIMIT=128
 -D HTTPD_ROOT="/home/apache-2.2.2"
 -D SUEXEC_BIN="/home/apache-2.2.2/bin/suexec"
 -D DEFAULT_PIDLOG="logs/httpd.pid"
 -D DEFAULT_SCOREBOARD="logs/apache_runtime_status"
 -D DEFAULT_LOCKFILE="logs/accept.lock"
 -D DEFAULT_ERRORLOG="logs/error_log"
 -D AP_TYPES_CONFIG_FILE="conf/mime.types"
 -D SERVER_CONFIG_FILE="conf/httpd.conf"
$ /home/apache/bin/apachectl -M

Loaded Modules:
 core_module (static)
 authn_file_module (static)
 authn_default_module (static)
 authz_host_module (static)
 authz_groupfile_module (static)
 authz_user_module (static)
 authz_default_module (static)
 auth_basic_module (static)
 cache_module (static)
 disk_cache_module (static)
 mem_cache_module (static)
 include_module (static)
 filter_module (static)
 log_config_module (static)
 env_module (static)
 expires_module (static)
 headers_module (static)
 usertrack_module (static)
 setenvif_module (static)
 proxy_module (static)
 proxy_connect_module (static)
 proxy_ftp_module (static)
 proxy_http_module (static)
 proxy_ajp_module (static)
 proxy_balancer_module (static)
 mpm_prefork_module (static)
 http_module (static)
 mime_module (static)
 status_module (static)
 autoindex_module (static)
 asis_module (static)
 info_module (static)
 cgi_module (static)
 negotiation_module (static)
 dir_module (static)
 actions_module (static)
 speling_module (static)
 alias_module (static)
 rewrite_module (static)
 so_module (static)
 php5_module (shared)
Syntax OK
$ ldd /home/apache/bin/httpd    

        linux-gate.so.1 =>  (0x00ed3000)
        libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0x006c4000)
        libaprutil-1.so.0 => /home/apache-2.2.2/lib/libaprutil-1.so.0 (0x00586000)
        libexpat.so.1 => /lib/libexpat.so.1 (0x0087a000)
        libapr-1.so.0 => /home/apache-2.2.2/lib/libapr-1.so.0 (0x00f91000)
        librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0x0093b000)
        libcrypt.so.1 => /lib/tls/i686/cmov/libcrypt.so.1 (0x005ce000)
        libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0x00115000)
        libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0x00964000)
        libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00413000)
        /lib/ld-linux.so.2 (0x00d4f000)

PHP Info

$ php -i

phpinfo()
PHP Version => 5.3.3

System => Linux ubuntu-xps 2.6.32-26-generic #47-Ubuntu SMP Wed Nov 17 15:59:05 UTC 2010 i686
Build Date => Nov 28 2010 19:21:06
Configure Command =>  './configure'  '--with-apxs2=/home/apache/bin/apxs' '--with-mysql=/home/mysql' '--with-curl=/usr/lib' '--with-zlib' '--enable-mbstring' '--enable-mbregex'
Server API => Command Line Interface
Virtual Directory Support => disabled
Configuration File (php.ini) Path => /usr/local/lib
Loaded Configuration File => (none)
Scan this dir for additional .ini files => (none)
Additional .ini files parsed => (none)
PHP API => 20090626
PHP Extension => 20090626
Zend Extension => 220090626
Zend Extension Build => API220090626,NTS
PHP Extension Build => API20090626,NTS
Debug Build => no
Thread Safety => disabled
Zend Memory Manager => enabled
Zend Multibyte Support => disabled
IPv6 Support => enabled
Registered PHP Streams => compress.zlib, php, file, glob, data, http, ftp, phar  
Registered Stream Socket Transports => tcp, udp, unix, udg
Registered Stream Filters => zlib.*, convert.iconv.*, string.rot13, string.toupper, string.tolower, string.strip_tags, convert.*, consumed, dechunk


This program makes use of the Zend Scripting Language Engine:
Zend Engine v2.3.0, Copyright (c) 1998-2010 Zend Technologies
$ php -m

[PHP Modules]
Core
ctype
curl
date
dom
ereg
fileinfo
filter
hash
iconv
json
libxml
mbstring
mysql
pcre
PDO
pdo_sqlite
Phar
posix
Reflection
session
SimpleXML
SPL
SQLite
sqlite3
standard
tokenizer
xml
xmlreader
xmlwriter
zlib

[Zend Modules]
$ ldd /home/apache/modules/libphp5.so

        linux-gate.so.1 =>  (0x00569000)
        libcrypt.so.1 => /lib/tls/i686/cmov/libcrypt.so.1 (0x00110000)
        librt.so.1 => /lib/tls/i686/cmov/librt.so.1 (0x001f6000)
        libmysqlclient.so.16 => /home/mysql-5.1.30/lib/mysql/libmysqlclient.so.16 (0x00356000)
        libz.so.1 => /lib/libz.so.1 (0x00142000)
        libm.so.6 => /lib/tls/i686/cmov/libm.so.6 (0x00157000)
        libdl.so.2 => /lib/tls/i686/cmov/libdl.so.2 (0x0017d000)
        libnsl.so.1 => /lib/tls/i686/cmov/libnsl.so.1 (0x00181000)
        libcurl.so.4 => /usr/lib/libcurl.so.4 (0x00198000)
        libxml2.so.2 => /usr/lib/libxml2.so.2 (0x001ff000)
        libc.so.6 => /lib/tls/i686/cmov/libc.so.6 (0x00e02000)
        libpthread.so.0 => /lib/tls/i686/cmov/libpthread.so.0 (0x001dd000)
        /lib/ld-linux.so.2 (0x00339000)
        libidn.so.11 => /usr/lib/libidn.so.11 (0x004ad000)
        liblber-2.4.so.2 => /usr/lib/liblber-2.4.so.2 (0x0032a000)
        libldap_r-2.4.so.2 => /usr/lib/libldap_r-2.4.so.2 (0x004df000)
        libgssapi_krb5.so.2 => /usr/lib/libgssapi_krb5.so.2 (0x00526000)
        libssl.so.0.9.8 => /lib/i686/cmov/libssl.so.0.9.8 (0x00f5c000)
        libcrypto.so.0.9.8 => /lib/i686/cmov/libcrypto.so.0.9.8 (0x00fa4000)
        libresolv.so.2 => /lib/tls/i686/cmov/libresolv.so.2 (0x00555000)
        libsasl2.so.2 => /usr/lib/libsasl2.so.2 (0x1ca3d000)
        libgnutls.so.26 => /usr/lib/libgnutls.so.26 (0x1eb4b000)
        libkrb5.so.3 => /usr/lib/libkrb5.so.3 (0x14a7f000)
        libk5crypto.so.3 => /usr/lib/libk5crypto.so.3 (0x19f18000)
        libcom_err.so.2 => /lib/libcom_err.so.2 (0x13a74000)
        libkrb5support.so.0 => /usr/lib/libkrb5support.so.0 (0x0c97e000)
        libkeyutils.so.1 => /lib/libkeyutils.so.1 (0x0d073000)
        libtasn1.so.3 => /usr/lib/libtasn1.so.3 (0x0b5c2000)
        libgcrypt.so.11 => /lib/libgcrypt.so.11 (0x09524000)
        libgpg-error.so.0 => /lib/libgpg-error.so.0 (0x07565000)

3. Debugging Info

$ sudo gdb ./httpd

GNU gdb (GDB) 7.1-ubuntu
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/apache-2.2.2/bin/httpd...done.

(gdb) b ap_process_request
Breakpoint 1 at 0x80b2409: file http_request.c, line 252.
(gdb) run -X -d /home/apache
Starting program: /home/apache-2.2.2/bin/httpd -X -d /home/apache
[Thread debugging using libthread_db enabled]

Breakpoint 1, ap_process_request (r=0x831e390) at http_request.c:252
252         if (ap_extended_status)
(gdb) n
235     {
(gdb) n
252         if (ap_extended_status)
(gdb) n
254         access_status = ap_run_quick_handler(r, 0);  /* Not a look-up request */
(gdb) n
255         if (access_status == DECLINED) {
(gdb) n
256             access_status = ap_process_request_internal(r);
(gdb) n
257             if (access_status == OK) {
(gdb) n
258                 access_status = ap_invoke_handler(r);
(gdb) n

Program received signal SIGSEGV, Segmentation fault.
0x0079b611 in php_handler (r=0x831e390)
    at /home/kawasaki/src/php/php-5.3.3/sapi/apache2handler/sapi_apache2.c:550
550             conf = ap_get_module_config(r->per_dir_config, &php5_module);
(gdb) n

(gdb) bt
#0  0x0079b611 in php_handler (r=0x831e390)
    at /home/kawasaki/src/php/php-5.3.3/sapi/apache2handler/sapi_apache2.c:550
#1  0x0807aa47 in ap_run_handler (r=0x831e390) at config.c:157
#2  0x0807db31 in ap_invoke_handler (r=0x831e390) at config.c:371
#3  0x080b2578 in ap_process_request (r=0x831e390) at http_request.c:258
#4  0x080af81e in ap_process_http_connection (c=0x8314348) at http_core.c:172
#5  0x080817c7 in ap_run_process_connection (c=0x8314348) at connection.c:43
#6  0x080cf1d4 in child_main (child_num_arg=<value optimised out>) at prefork.c:640
#7  0x080cf434 in make_child (s=0x8109f78, slot=0) at prefork.c:680
#8  0x080d01fa in ap_mpm_run (_pconf=0x81010a8, plog=0x814b1d0, s=0x8109f78)
    at prefork.c:956
#9  0x0806872f in main (argc=135262496, argv=0x0) at main.c:717

参考: Apache Debugging Guide: Using gdb

落ちている箇所、php_handler (php-5.3.3/sapi/apache2handler/sapi_apache2.c:550)のソースコード

538 static int php_handler(request_rec *r)
539 {
540     php_struct * volatile ctx;
541     void *conf;
542     apr_bucket_brigade * volatile brigade;
543     apr_bucket *bucket;
544     apr_status_t rv;
545     request_rec * volatile parent_req = NULL;
546     TSRMLS_FETCH();
547
548 #define PHPAP_INI_OFF php_apache_ini_dtor(r, parent_req TSRMLS_CC);
549
550     conf = ap_get_module_config(r->per_dir_config, &php5_module);
551
552     /* apply_config() needs r in some cases, so allocate server_context early */
553     ctx = SG(server_context);
554     if (ctx == NULL || (ctx && ctx->request_processed && !strcmp(r->protocol, "INCLUDED"))) {
555 normal:
556         ctx = SG(server_context) = apr_pcalloc(r->pool, sizeof(*ctx));
557         /* register a cleanup so we clear out the SG(server_context)
558          * after each request. Note: We pass in the pointer to the
559          * server_context in case this is handled by a different thread.
560          */

561         apr_pool_cleanup_register(r->pool, (void *)&SG(server_context), php_server_context_cleanup, apr_pool_cleanup_null);
562         ctx->r = r;
563         ctx = NULL; /* May look weird to null it here, but it is to catch the right case in the first_try later on */
564     } else {
565         parent_req = ctx->r;
566         ctx->r = r;
567     }
568     apply_config(conf);

php5 モジュールの設定情報読み込み時にSegmentation fault(11)でApacheがCrashしている。 理由がわからない。とりあえず調査はここで止め、Apacheの設定ファイルからはphp5 モジュールのロード設定をはずしている。 早まった考えかもしれないがPHPを使うのやめてしまおうかと思っている今日この頃。PHPなんて。。

おわり

追記 2010.12.05

Apache-2.2.2、PHP-5.3.3共にアンインストールして再インストールしたところ問題なく動いてしまった。evidenceを集め、問題を特定する、それしかないと思い込み(だらだらと)調査していたのでとりあえず再インストールしてみる選択肢は頭になかった。結論として、(素人ぽくてアレなんだけど)困ったときは再インストールしろ – ということだ。

Posted in: Environment Setup

Tags: , , , , ,

Python – thisモジュール誕生にまつわる”深イイ話”

Pythonにはthisモジュールという「The Zen of Python」(参考1)を出力するだけのモジュールがある。このモジュール、中身(参考2)を見てみると分かるが、総ステップにしてわずか28行、ROT13暗号化(参考3)された文字列を復号化するだけの単純であえて記事にするには取るに足らない内容かもしれない。ただしこのモジュールが作られた背景はとても面白い。Barry Warsaw氏が記事「import this and The Zen of Python」でthisモジュールが誕生にまつわる深イイ話を紹介している。

import this and The Zen of Python」の一部簡訳

2001年秋、Foretec Seminar社はのInternational Python Conference #10(以下IPC10、Pyconの前身となるカンファレンス)の準備をしておりPythonコミュニティからそのカンファレンスのスローガンを求めていた。スローガンはTシャツにもプリントされる予定だった。Guideや、Fred、Jeremyや著者達はかつてはForetec Seminar社に所属していたがPythonlabsを結成する2000年に同社を去っている。そしてPythonlabsはPythonコミュニティからのスローガン応募の審査と勝者の選定を担当することになった。応募は500くらいあったが、どれもひどいものだった。Timと著者は1つに絞られるまで何度となく選別作業を行い
最終的に”import this”を選んだ。理由は”import this”という言葉の持つふざけた、小バカにしたようなトーンが好きだったからという。

著者たちはこの”import this”をスローガンに選んですぐにthisモジュール(this.py)を実装した。モジュールは「The Zen of Python」を出力するだけのものだったが途中TimやGuidoの提案でrot13で暗号化して内容を少し難読化する工夫がされたりもした。IPC10が終わってすぐ、彼らはこのイベントを記念してthisモジュールをPython2.2.1ブランチにコミットした。この時、著者の提案で他の誰にも知られないようにするためにソース管理システムのチェックイン通知機能を停止し、こっそりこのモジュールをPython2.2.1のブランチに含めたのだ。これらのことは彼ら以外に誰にも知らせず内緒で行われた。著者いわく、この彼らの仕込んだeaster egg(thisモジュールのこと。ソフトウェアでいうeaster eggとは隠しコマンドとか、隠しクレジットのようなもの)が誰かに見つかるまではしばらく時間がかかったそうだ。

Barry Warsaw氏が同記事を「That was all back in the day when the Python community had a sense of humor」という一文で締めくくっているように、この記事を読むと当時のPythonコミュニティがいかにユーモア溢れたものだったのかが感じられる。phython-2.2.1がリリースされたのは2002年4月10日で、それからどれくらい経ってこのthisモジュールが発見されたのか分からないが初めて発見した人は絶対ほっこりしたことだろう。得意不得意は抜きにして自分はこのエピソードを読んでPythonという言語が好きになった。

参考1: 「The Zen of Python」とimport thisの出力結果

The Zen of Python」はPythonハッカー、Tim Petersによって書かれた有名な文章でPython設計哲学を要約したようなものと言われている。 Barry Warsaw氏の記事によると起源はTim Peters氏による1999年6月4日のPython-listへのこの投稿のようだ。以下、Pythonインタラクティクモードでimport thisを実行し「The Zen of Python」を表示させる。

[kawasaki@ubuntu:~] $ python
Python 2.6.5 (r265:79063, Apr 16 2010, 13:09:56)
[GCC 4.4.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import this

The Zen of Python, by Tim Peters

Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
>>>

参考2: this.py

this.pyの中身を見てみる。 意味不明なコードを次の参考3で解説するROT13で複合化することで「The Zen of Python」を出力している。
/usr/lib/python2.6/this.py

s = """Gur Mra bs Clguba, ol Gvz Crgref

Ornhgvshy vf orggre guna htyl.
Rkcyvpvg vf orggre guna vzcyvpvg.
Fvzcyr vf orggre guna pbzcyrk.
Pbzcyrk vf orggre guna pbzcyvpngrq.
Syng vf orggre guna arfgrq.
Fcnefr vf orggre guna qrafr.
Ernqnovyvgl pbhagf.
Fcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.
Nygubhtu cenpgvpnyvgl orngf chevgl.
Reebef fubhyq arire cnff fvyragyl.
Hayrff rkcyvpvgyl fvyraprq.
Va gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.
Gurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.
Nygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.
Abj vf orggre guna arire.
Nygubhtu arire vf bsgra orggre guna *evtug* abj.
Vs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.
Vs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.
Anzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!"""


d = {}
for c in (65, 97):
    for i in range(26):
        d[chr(i+c)] = chr((i+13) % 26 + c)

print "".join([d.get(c, c) for c in s])

参考3: ROT13

ROT13は定められた置き換えマップにもとづいて文字を置き換えるだけの単純な暗号方式である。 次の変換マップに基づいて文字を変換するので例えばA→N、B→O、C→Pのように変換される。

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
                            ↓↑
NOPQRSTUVWXYZABCDEFGHIJKLMnopqrstuvwxyzabcdefghijklm

thisモジュールではこの変換マップはグローバル変数dに格納されており、次のように表示させてみる。

>>> this.d
{'A': 'N', 'C': 'P', 'B': 'O', 'E': 'R', 'D': 'Q', 'G': 'T', 'F': 'S', 'I': 'V', 'H': 'U', 'K': 'X', 'J': 'W', 'M': 'Z', 'L': 'Y', 'O': 'B', 'N': 'A', 'Q': 'D', 'P': 'C', 'S': 'F', 'R': 'E', 'U': 'H', 'T': 'G', 'W': 'J', 'V': 'I', 'Y': 'L', 'X': 'K', 'Z': 'M', 'a': 'n', 'c': 'p', 'b': 'o', 'e': 'r', 'd': 'q', 'g': 't', 'f': 's', 'i': 'v', 'h': 'u', 'k': 'x', 'j': 'w', 'm': 'z', 'l': 'y', 'o': 'b', 'n': 'a', 'q': 'd', 'p': 'c', 's': 'f', 'r': 'e', 'u': 'h', 't': 'g', 'w': 'j', 'v': 'i', 'y': 'l', 'x': 'k', 'z': 'm'}

参考2で紹介されたthis.pyの最後の行(↓)はROT13で暗号化された文字列(s)を1つずつ取り出し変換マップdに基づいて複合化している。

 print "".join([d.get(c, c) for c in s])

ちなみにPython2系にはROT13の実装は標準で組み込まれており次のように直接decode関数に’rot13′を指定することでROT13で暗号化された文字列sを複合化することができる。

>>> this.s
"Gur Mra bs Clguba, ol Gvz Crgref\n\nOrnhgvshy vf orggre guna htyl.\nRkcyvpvg vf orggre guna vzcyvpvg.\nFvzcyr vf orggre guna pbzcyrk.\nPbzcyrk vf orggre guna pbzcyvpngrq.\nSyng vf orggre guna arfgrq.\nFcnefr vf orggre guna qrafr.\nErnqnovyvgl pbhagf.\nFcrpvny pnfrf nera'g fcrpvny rabhtu gb oernx gur ehyrf.\nNygubhtu cenpgvpnyvgl orngf chevgl.\nReebef fubhyq arire cnff fvyragyl.\nHayrff rkcyvpvgyl fvyraprq.\nVa gur snpr bs nzovthvgl, ershfr gur grzcgngvba gb thrff.\nGurer fubhyq or bar-- naq cersrenoyl bayl bar --boivbhf jnl gb qb vg.\nNygubhtu gung jnl znl abg or boivbhf ng svefg hayrff lbh'er Qhgpu.\nAbj vf orggre guna arire.\nNygubhtu arire vf bsgra orggre guna *evtug* abj.\nVs gur vzcyrzragngvba vf uneq gb rkcynva, vg'f n onq vqrn.\nVs gur vzcyrzragngvba vf rnfl gb rkcynva, vg znl or n tbbq vqrn.\nAnzrfcnprf ner bar ubaxvat terng vqrn -- yrg'f qb zber bs gubfr!"
>>> this.s.decode('rot13')
u"The Zen of Python, by Tim Peters\n\nBeautiful is better than ugly.\nExplicit is better than implicit.\nSimple is better than complex.\nComplex is better than complicated.\nFlat is better than nested.\nSparse is better than dense.\nReadability counts.\nSpecial cases aren't special enough to break the rules.\nAlthough practicality beats purity.\nErrors should never pass silently.\nUnless explicitly silenced.\nIn the face of ambiguity, refuse the temptation to guess.\nThere should be one-- and preferably only one --obvious way to do it.\nAlthough that way may not be obvious at first unless you're Dutch.\nNow is better than never.\nAlthough never is often better than *right* now.\nIf the implementation is hard to explain, it's a bad idea.\nIf the implementation is easy to explain, it may be a good idea.\nNamespaces are one honking great idea -- let's do more of those!"

おわり。

Posted in: Programming, Translation

Tags: ,

OpenSSH -SOCKSプロキシ経由でSSH接続

外部からのssh接続を受け付けていないLAN内のサーバに外部からログインするために踏み台サーバを経由してLAN内サーバにログインするというよくある話です。今回試したのはSSHをSOCKSプロキシとして利用して、そのSOCKSプロキシ経由して目的のLAN内サーバに一発ログインする方法です。

SOCKS(RFC1928) とはさまざまなアプリケーションが間にファイアーウォールを挟んでいても安全に快適にやり取りができるようにすることを目的として作られたプロトコルのことで、SOCKSプロキシはSOCKSプロトコルを受け取りファイアウォール内外との接続を可能にします。 これに関してはIPAのコンテンツに図付きの解りやすい説明があります。参考までに > SOCKS

ちなみにSOCKSプロキシの利点はSOCKS対応のアプリケーションであればSOCKSプロキシ経由でLAN内部のサーバにアクセスが可能なことで、例えばSOCKS対応ブラウザであればSOCKSプロキシ経由でLAN内のコンテンツが閲覧できます。自分はこのSOCKSプロキシ経由でのLAN内ドキュメントのブラウジングは多用してます。

SOCKSプロキシの作成

まずはSOCKSプロキシの立ち上げです。OpenSSHのダイナミックポートフォワード機能を使います。

ダイナミックポートフォワードはsshをSOCKSプロキシとして振舞うことを可能にします。sshでアクセス先ホストと DynamicFoward(-D)でポートを指定することでlocalhostにSOCKSプロキシが立ち上がり指定のTCPポート(SOCKSプロキシサーバは基本的は1080ですが、割り当て可能なポートであればどのポートでもOK)をlocalhost側からログイン先ホストのSSHサーバに転送することができるようになります。もちろん経路は暗号化され、現状のサポートプロトコルはSOCKS4とSOCKS5です。
例えばJumpサーバにDynamicFoward(-D)1080でログインすると、Jumpサーバにポート1080を転送するSOCKSプロキシが localhostに立ち上がり、そのlocalhost:1080に対してSOCKS4またはSOCKS5プロトコルで接続することでJumpサーバを経由して通信を行うことができます。

localhost ポート1080のJumpサーバへのダイナミックフォワードは次のように-Dオプションで行います。

ServerA$ ssh -2 -D 1080 -l <Account> <JumpServer>

毎回-Dオプション指定が面倒な場合は次のようにconfg(ssh_config)にDynamicForwardの記述しておきましょう。

$ cat ~/.ssh/config

Host JumpServer
   User        <Account>
   HostName  JumpServeer
   Protocol 2
   ForwardAgent  yes
   DynamicForward 1080

SOCKSプロキシを使ったSSH接続

次に上で事前に作成したSOCKSプロキシを使ってLAN内のサーバにSSH接続をします。 netcatでSOCKSプロキシを経由してlocalhostから目的のLAN内サーバ(ServerB)間にnetcat tunnelを作成します。ServerBにはそのnetcat tunnelを通じて接続します。

ServerA$ ssh -2 -l <Account> -o 'ProxyCommand nc -x localhost:1080 %h %p' <ServerB>

netcat のプロキシ指定は-xオプションで行います。 ここでは事前に作成したSOCKSプロキシ(localhost:1080)を指定。 netcat tunnelの作成コマンドはおなじみProxyCommandに記述します。こちらも毎回長いオプション入力を避けるために config(ssh_config)設定をしましょう。

$ cat ~/.ssh/config

Host ServerB
   User        <Account>
   Protocol 2
   ForwardAgent  yes
   ProxyCommand nc -x localhost:1080 -w1 %h %p

注意点
netcatにはGNU本家版とそれ以外にいくつか派生がありますが -x オプションの利用可能なnetcatをインストールしてください。オリジナルのnetcatGNU netcatには-xオプションはありません。ここで使用しているnetcatはIPv6に対応しているOpenBSD netcatです。

SOCKSプロキシを経由しないでSSH接続

別解としてProxyCommandでJumpからBのnetcat tunnelを作成してServerAからServerBにログインする方法があります。詳しくは「DSAS開発者の部屋:OpenSSH クライアントの proxy — 踏み台サーバを経由しての ssh」を参考にしてもらうとしてここでは次のようにログインすることができます。

ServerA$ ssh -2 -o 'ProxyCommand ssh  Jump nc -w1 %h %p' ServerB

ProxyCommand でプロキシ設定を行うため事前に別コンソールで何かを用意する必要がなく間違いなく楽。それと比べて事前にSOCKSプロキシを立てる必要がある SOCKSプロキシ経由のログインは面倒です。ではどうしてこんな設定を選んだのか? 理由は単純で、当初は楽な方法で行く予定でいたものの、結局Jumpサーバがnetcatが使えない(ncはおろかsshコマンド以外ほとんど何も使えない)環境だったからです。そこでいくつか調べて行き着いたのがこのSOCKSプロキシ経由でのSSHログインだったというわけです。まさに苦肉の策。でも回り道した分少しだけOpenSSHに詳しくなりました。

おわり。

Posted in: Environment Setup

Tags: , , , , ,