PPTPのクライアント

アマゾンの EC2マシンからデータセンターの VPNPPTP接続してみた。マシンは chef で作ってブートストラップ(chef bootstraper for amazon-linux · GitHubruby は 1.9.3 に)した Amazon-linuxマシン。さらに手で「yum update」した。あと、なにがどこにあるのか分からないので locate も入れておく「sudo yum install mlocate」。

yum list」から探した pptp関係のパッケージ

  • ppp.i686 2.4.5-5.5.amzn1 amzn-main
  • ppp-devel.i686 2.4.5-5.5.amzn1 amzn-main
  • pptp.i686 1.7.2-8.1.1.amzn1 amzn-main
  • pptp-setup.i686 1.7.2-8.1.1.amzn1 amzn-main

ということで「sudo yum install pptp」、そうすると依存性で ppp までは来る。
設定なんかは
EZ-NET: PPTP-VPN に接続する (CentOS 5.6) - Linux の使い方を参考に。ということで setup もインストールしよう「sudo yum install pptp-setup」。

そして設定をつくり、接続してみる。結構あっけなく繋がる。

[ec2-user@ip-10-46-97-227 ~]$ sudo pptpsetup --create PPTP --server <IP> --username <> --password <> --encrypt
[ec2-user@ip-10-46-97-227 ~]$ sudo pppd call PPTP updetach
Using interface ppp0
Connect: ppp0 <--> /dev/pts/2
CHAP authentication succeeded
MPPE 128-bit stateless compression enabled
local  IP address 192.<>
remote IP address 172.<>

結果の IP は使ってる VPNがそうなんだということ。

そしてルート情報

[ec2-user@ip-10-46-97-227 ~]$ sudo route add -net 192.<>.0 gw 172.<> netmask 255.255.255.0

EC2機からデータセンター機見えるし、データセンター機からも EC2機がデータセンター内の IP で見えるし。

ルート情報

Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
<IP>    ip-10-46-97-1.e 255.255.255.255 UGH   0      0        0 eth0
ip-172-<>. *               255.255.255.255 UH    0      0        0 ppp0
192.<>.0     ip-172-<>. 255.255.255.0   UG    0      0        0 ppp0
10.46.97.0      *               255.255.255.0   U     0      0        0 eth0
default         ip-10-46-97-1.e 0.0.0.0         UG    0      0        0 eth0

三行目が追加した EC2機から VPN(データセンター)へのルート情報。

EC2側のIP情報は隠してないけど、インスタンス落としたんでもうない。

PuTTYで生成した公開鍵を使う

どこで見たんだっけな、PuTTYgen で生成したキーペアについて。公開鍵を Linux機に仕込む。

ssh-keygen -i -f id_rsa.pub >> authorized_keys

ちなみに -iオプションは

     -i      This option will read an unencrypted private (or public) key file
             in SSH2-compatible format and print an OpenSSH compatible private
             (or public) key to stdout.  ssh-keygen also reads the RFC 4716
             SSH Public Key File Format.  This option allows importing keys
             from several commercial SSH implementations.

コマンドラインのみで Dropbox

遅ればせながらDropbox(Dropbox)、で、Linuxではどうすればいいのだろう。勿論サイトに Linux版もあるのだけど GUI操作が前提の様だ。コマンドラインだけの環境ではどうしたら良いのだろう。
この辺を参考にしてみた。

それからその「Dropbox for Linux」の頁。

Linux版の説明頁には Source からのインストールの項もあるのだけど結局 GUI操作が必要になる模様。

基本的な流れ

Dropboxのインストールは上記 GUI版では、オープンソース(GPL)のクライアントソフトをインストールする所から始まる。それが上記頁に挙げられているパッケージ。そしてその GUIクライアントの初回起動時に Web上のストレージとの同期を行うプロプライエタリなプログラムをダウンロードしてくる。という流れになってる模様。
GUI環境が無い場合の注意として、上記頁にはコマンドライン版(CLI)版の記述もある(What if I don't use Nautilus or X?、http://www.dropbox.com/download?dl=packages/dropbox.py)。上に挙げた Wiki に書かれた操作の一部をまとめたものの様だ。

全体的なこと

どうも全体的にみて、個人が一人で使うという想定の仕組みになっているような気がする。自動ダウンロードされるデーモンプログラム(やその補助類)、設定ファイルなんかはホームディレクトリ直下に配置される、.dropbox-dist, .dropbox とか。デーモンプログラムも上記 Pythonスクリプトでユーザ権限で実行する感じ。
まあ、ちょっとなんかすればマルチユーザで使う用のセッティングも出来るでしょう。

実行

Debian/GNU Linux (lenny) にて

  1. 上記 Pythonスクリプトをダウンロード
  2. python dropbox.py」
    • 下記ずっとユーザ権限での実行
    • コマンドのヘルプが返る、その示唆に従い
  3. python dropbox.py start」
    • Dropboxデーモン入ってない、「-i」オプション付けたら、といわれる
  4. python dropbox.py start -i」
    1. 「y」と答えるわけだ
    2. ダウンロード始まる、ちょっと掛かる
    3. 初回アカウント接続にはグラフィカル環境必要といわれる
      • それは無視せざるを得ない
      • ここではまだ .dropbox はできてない、.dropbox-dist にはいろいろ入ってる
  5. python dropbox.py start」
  6. python dropbox.py status」
    • Waiting to be linked to an account...
    • ずっとかわらない
  7. python dropbox.py stop」
  8. 「sqlite3 .dropbox/dropbox.db 'SELECT * FROM config;'」
    • なんか出てくる。host_id の値をメモる
  9. TextBasedLinuxInstall の示唆に従い host_id の値を Base64デコード
  10. どっか別のところから、普通のブラウザで下記にアクセス
    1. アカウントを訊かれたら登録済みのアカウントを答える
    2. そっちはもう忘れちゃっていい、けどまあ続き、Linux での接続を待ってもいいかな
    • その後試したがその儘 Linuxw3mブラウザでこの URLアクセスしたらアカウント登録出来た、これで本当にテキスト端末のみ。(この項翌日追記)
  11. 改めてインストール中の Linux で作業「mkdir Dropbox
  12. python dropbox.py start」
    • Start した後同期が始まる、適宜 status を見るとか

こんな感じ、適宜「python dropbox.py stop」する。必要なら /etc/init.d スクリプトとか作って自働起動にしてもいいか。その辺のヒントやサンプルスクリプトも上記リンク先にあります。

同期相手の識別はインストール時に発行される一意の HOSTID を使っているという事でしょうね。その HOSTID と登録アカウントの対応付けを最初に行う、普通は GUIクライアントから行うのだけど、Webからブラウザでも出来るのでそうする。

dropbox.py のヘルプ

Dropbox command-line interface

commands:

 status       get current status of the dropboxd
 help         provide help
 puburl       get public url of a file in your dropbox
 stop         stop dropboxd
 start        start dropboxd
 filestatus   get current sync status of one or more files
 ls           list directory contents with current sync status

Twitterへのメールからの投稿

Twitter 始めました、(hs9587) on Twitter
で、だ。メールを送ったら Twitter投稿してくれるサービス無いかなと。いかにもありそうだけど探すの面倒だし、自分用に作った。これで出先からの投稿が出来るようになった。

環境というか方針としては、CentOSPostfixSMTPサービスが動いてる所にメールを送り、それを Rubyスクリプトに渡してhttp://apiwiki.twitter.com/Twitter-REST-API-Method%3A-statuses%C2%A0updateをどうこうする。

  1. Postfix が特定のアドレスへのメールを捕まえる
  2. それを Postfix から外部コマンドへ渡す
  3. 渡された RubyスクリプトTwitter API で投稿する

Postfix 辞典 (DESKTOP REFERENCE)

Postfix 辞典 (DESKTOP REFERENCE)

とか参考に

Postfix が特定のアドレスへのメールを捕まえる

Postfix 辞典」逆引きリファレンス27「外部コマンドを利用したい」を参考に「transport_maps = hash:/etc/postfix/transport」の設定をする。

/etc/postfix/transport

twitter-update@<サーバアドレス> twitter_api:
twitter-timeline@<サーバアドレス> twitter_api:
twitter-mentions@<サーバアドレス> twitter_api:
twitter-user@<サーバアドレス> twitter_api:

取り敢えず twitter-update しか実装してないけどタイムラインぐらい将来取りたいのでキーワード書いとく。

あと、これらのアドレスが有効になるのは、「transport_maps = <云々>」の設定と同様に /etc/postfix/main.cf に「local_recipient_maps =」として(= の右辺は無し)任意の @左辺アドレスを有効にしているから。そもそもなぜそうしてるかというと、それはまあいろいろある。そちらのメールアドレス名前空間からはこの4つの名前を奪った事になる。

書き換え後は「sudo /usr/sbin/postmap /etc/postfix/transport」を忘れずに。

そして「twitter_api:」というのは次

それを Postfix から外部コマンドへ渡す

上記キーワード「twitter_api:」は転送エージェントの指定と言う事になっている、それは下記に定義したの。

/etc/postfix/master.cf

twitter_api unix -      n       n       -       -       pipe                    
  user=<ユーザ名> argv=/home/<ユーザ名>/projects/twitter_api.rb ${sender} ${recipient}

最初 master.cf での定義と思わず main.cf に書いててはまった。いろいろエラーになったり或は何も起こらなかったり、ログを見れば上記 transport でメール捕まえてはいるのだが twitter_api 見付らないとエラーになってたり。
設定は /etc/postfix/master.cf です、「Postfix 辞典」逆引きリファレンス27「外部コマンドを利用したい」の記述はちょっとわかり難かった。

改行の作法とか、「unix - n n - - pipe」の項目については適宜 Postfix の資料を見よ。

Postfix詳解―MTAの理解とメールサーバの構築・運用

Postfix詳解―MTAの理解とメールサーバの構築・運用

第13章とか。

${sender} ${recipient} 以外に使用できる変数は「Postfix 辞典」機能リファレンス「pipe」p.111 とか。subject はないのね、したらまあこの二つくらいか。

渡された RubyスクリプトTwitter API で投稿する

Rubyスクリプト側での処理の分岐は第二引数 ${recipient} を見ることにしよう。登録されてる ${sender} に応じた Twitterアカウントで Twitter REST API に出掛ける。取り敢えず認証は甘い、まあ、自分専用だし。変なのが来る様ならブロックしましょう(それで間に合うのか、間に合うといいな)
メール内容は標準入力でやってくる。はじめ subject を Twitter投稿内容にすることも考えたが、subject なので Base64エンコードされてる。なので本文一行目(JISコードというか、ISO-2022-JP)を投稿する事にしよう。

#!/usr/bin/ruby
# -*- coding: utf-8 -*-
require 'nkf'
require 'net/http'
Net::HTTP.version_1_2
Trusted = [
  '<投稿者メールアドレス>',
  ]
Twitt = Struct.new :acount, :password
Twitts = {
  '<メールアドレス@の前>' => Twitt.new('<Twitterアカウント>', '<Twitterパスワード>')
  }

sender, recipient, = ARGV
File.open('/home/<ユーザ名>/projects/'+Time.now.strftime('%Y%m%d%H%M%S'), 'w'){ |f|
f.puts sender, recipient, ''
if Trusted.include? sender then
  #File.open('/home/<ユーザ名>/projects/'+Time.now.strftime('%Y%m%d%H%M%S'), 'w'){ |f| f.puts ARGV, $stdin.read }
  twitt = Twitts[sender.split('@')[0]]
  case recipient
    when 'twitter-update@<サーバアドレス>' then
      null_line = false
      doing = ''
      $stdin.readlines.each do |line|
         (doing = line.chomp; break) if null_line
         null_line = true if 1 == line.length
      end # $stdin.readlines.each do |line|
      f.puts doing
      request = Net::HTTP::Post.new('/statuses/update.json')
      request.basic_auth twitt.acount, twitt.password
      response = nil
      Net::HTTP.start('twitter.com',80) do |http|
        response = http.request(request, "status=#{NKF.nkf('-Jw', doing)}")
      end # Net::HTTP.start('twitter.com',80) do |http|
      f.puts response.body
    else
  end # case recipient
else# if Trusted.include? sender
  f.puts $stdin.read
end # if Trusted.include? sender
}

初め openuri でどうかなと思ったけど、Post だし基本認証だし Net::HTTP を直接使う。あと、gem にも Twitterクライアントっぽいもの幾つかあるっぽいのだけど、よく分からないので全部手で書いた。
メール本文の一行目、空行の次の行を見分ける所どうでしょう。メール全体をパースしたりしないでいいよね、でもちょっと手抜き過ぎか。
日本語は最初化けっぽかった、NKFユニコードにしたらなんとか。
Trusted配列と、Twittsハッシュを二つ持ってる必要は無いよね、ハッシュに(キーが)あるなら OK とかそういうロジックで良い筈。

課題とか

そもそも自前で自由に出来る SMTPサービス(Postfixサーバ)があるという前提だし、大仕掛けに過ぎるような気もする。foward処理を頑張ればここまで仕掛け大きくしなくても良い様な気もする。いかがでしょうか
transport設定いじるという大仕掛けの割りに Rubyスクリプトをユーザホームディレクトリに置いてるのも不釣合いかな。まあ、そんな特権的なユーザなんだという風に解釈しましょう。

あとは Rubyスクリプトで、${recipient} による処理の分岐やタイムラインの取得、と、それを ${sender} に送るとか。かな。
上記スクリプト自体もリファクタリングの余地あるよね、ちょっと、いろいろ、大分。

それはそれとして

そして作ったあたりで「モバツイッターとかではダメなんですか?」とツイッター返されました。
どうなんでしょう、モバツイッターの説明の「携帯電話、iPhoneWindows Mobileで快適にご利用いただけます。」を見て、自分のかなり古いPHSが対象外と思い込んでしまってちゃんと検討してない。
モバツイッターとは?」の説明からはそれくらいしか読み取れなくてよく分からない。
どうなんでしょう?