Thursday, January 17, 2013

sysctl.confのtokenにピリオドを使いたい

最近、LVS(UltraMonkey)の設定をしていた時に気付いたことがあったのでメモ。
この時は、事情でVLAN なインタフェース(例: eth0.123)にをつかって、LVSの DR(Direct Route)モードで設定を行う必要があった。

この場合、振り分け先のサーバ(ldirectord.cf の real= 行に記述するサーバ。いわゆる「リアルサーバ」)上に lo:0 にも /32 で VIP を設定する必要がある。
これに伴い、lo:0 が持っている VIP への ARP リクエストを無視させる/ARPを出す時にVIPを使わないように制限する必要があるので、
/etc/sysctl.conf 
に、例えばこんな感じの設定を行う必要がある。
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.eth0.arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.eth0.arp_announce = 2
参考情報としては、例えば


の「Real Servers」あたりを参照のこと。

さて、ここからが本題である。
上記の eth0 の部分が、VLAN 123 に対応するインタフェースで eth0.123 だったらどうなるか?

そのまま書いてしまうと、token の部分の要素のセパレータの . (ピリオド)と、eth0 と VLAN番号の間の . (ピリオド)が被っているので /proc/sys 以下にマッピングされるときに、

net.ipv4.conf.eth0.123.arp_ignore

なら

/proc/sys/net/ipv4/conf/eth0/123/arp_ignore 

と変換されてしまい、エラーになる。クォートもできないようだ。

そこで、man  sysctl を良く読んでみると、
SYSCTL(8)                    System Administration                   SYSCTL(8)
NAME
       sysctl - configure kernel parameters at runtime
SYNOPSIS
       sysctl  [options] [variable[=value]] [...]   sysctl -p [file or regexp]
       [...]
DESCRIPTION
       sysctl is used to modify kernel parameters at runtime.  The  parameters
       available  are  those  listed under /proc/sys/.  Procfs is required for
       sysctl support in Linux.  You can use sysctl to  both  read  and  write
       sysctl data.
PARAMETERS
       variable
              The  name  of  a key to read from.  An example is kernel.ostype.
              The '/' separator is also accepted in place of a '.'.

と書いてある。特に最後の赤字で強調した行に注目。
全体としてどういう仕様になるのか、いまいちあいまいなのだが、とにかく . (ピリオド)の代わりに / (スラッシュ)も使えるように見える。

実際やってみると、上記のパターンであれば、
net.ipv4.conf.all.arp_ignore = 1
net/ipv4/conf/eth0.1110/arp_ignore = 1
net.ipv4.conf.all.arp_announce = 2
net/ipv4/conf/eth0.1110/arp_announce = 2
の2行目と4行目のように書いてやればよく、挙動としては、最初にあらわれた / (スラッシュ)か . (ピリオド)が、トークンの部分の要素のセパレータとして使われる。…ので、上記は正常に反映できるし、これは行ごとにばらばらでよい。

余談だが、sysctl は(Ubuntuでは) procps パッケージに含まれており、当該部分の処理は、sysctl.c の
 73 static void slashdot(char *restrict p, char old, char new)
 74 {
 75         int warned = 1;
 76         p = strpbrk(p, "/.");
 77         if (!p)
 78                 /* nothing -- can't be, but oh well */
 79                 return;
 80         if (*p == new)
の 76行目で strpbrk(3)関数に "/."  (スラッシュとピリオド)を渡しているところが対応する。
(procps のバージョンは 1:3.3.3-2ubuntu3)

実は、strpbrk なんて初めて知ったのだが、man してみると以下の通り。
STRPBRK(3)                 Linux Programmer's Manual                STRPBRK(3)
NAME
       strpbrk - search a string for any of a set of characters
SYNOPSIS
       #include <string.h>
       char *strpbrk(const char *s, const char *accept);
DESCRIPTION
       The  strpbrk() function locates the first occurrence in the string s of
       any of the characters in the string accept.
  :
第2引数の文字列に含まれる任意の文字が、第一引数に渡した文字列中に最初にあらわれる位置を返す…と。
いや、Cの標準ライブラリも奥が深いですね...

Sunday, January 13, 2013

L2 over SSH


このところ ssh tunnel ネタが多いが、実は ssh を使って port forwarding だけではなく、L3トンネルや L2トンネルを作れるのはそんなに知られていないように思う。実際、自分も Software Design 2012/10月号の、川本(@togakushi)さんの記事「SSH力をつけよう!」を読むまで知らなかった。

余談だが、この記事は本当にすばらしい。chef 特集につられて買った号だったのだが、編集部の気合いを感じた一冊だった。


まず、L3トンネルのやり方から。
port forwarding とは違い、今度はオプションに -L ではなく -w を使う。
例えば

  $ ssh -w 0:0   root@remote_host

とすれば、ローカルとリモートの双方に tun0 という tunnel device (tun) が作成され、
-w の指定値は、

  $ ssh -w any:any   root@remote_host

のように、any:any とすれば、tun1 とか tun2 とか、ローカルリモートそれぞれで tunnel device 番号の空きの若いものから自動的に採番してくれる。

こうして作成した tunX にそれぞれ適切に IP address を割り当てれば IP レベル(L3 レベル)で通信できるようになる。


ところで、この仮想化の時代、L3トンネルが張れるなら、L2 トンネルも張れないのか?と思うのが、人情だと思う。Software Design の記事では、スペースの関係か触れられていないのだが、実は、以下のように ssh のオプション指定によって、tunnnel device (tunX)だけでなく、Encapsulation が Ethernet に見えるような L2 tunnel、つまり tap も作成できる。

  $ ssh -w any:any  -o Tunnel=ethernet  root@remote_host

tap を作成する場合もやはり -w は必要で、指定値は tun の時と同じように使われる。
つまり、tap1 なり tap9 なりと(空いていれば)好きな番号の tap device を作れる。
(1/17追記)
なお、/etc/ssh/sshd_config や /etc/ssh/ssh_config に TunnelPermit や Tunnel 等の指定値が明示的に記述されていると強制的に tun になってしまうことがあるので注意のこと。


さて、実はここからが本題である。
下図のようにHOST1 と HOST2 があるとして、この2台の間は、proxy なり、NATなり、(多段)port forwarding なりの何らかの手段で ssh 接続可能だとする。(多段)port forwarding については前にも書いたので参考まで。

図の赤い線で結んだssh 接続の間には proxy があっても NATがあってもよい。とにかく、HOST1とHOST2の間でssh接続し、上で説明したオプションを指定して tap を接続してしまうことによって、仮想的に1枚のL2面を作れたことになる。(通信品質についてはいわずもがななので、そこはつっこまないように)

さらに図のように、作成した tap をbridge で VMの仮想NICに接続してしまえば、踏み台の向こうの環境で動いているVMに対して、L2レベルで接続できるので、例えば HOST2 から HOST1 上のVMに対してDHCPでアドレスを払いだす…等といったことも可能である。
(HOST2の構成が図とはちょっと違うのだが)実際やってみたら、問題なく動くし、やろうと思えば3ノード以上でフルメッシュ構成にするのも可能である。(ループが発生しないように若干注意が必要だが...)
世の中では、VXLAN だの STT だの NVGRE といった L2 over L3 技術や、SPB やら TRILL (やそれらの拡張)といった L2 over L2 技術で百花繚乱状態だが、こういう poor man's solution もあるよということで(笑)

Wednesday, January 9, 2013

sshトンネル作成時の -L 指定値

昨日も触れた ssh トンネルの張り方は、ぐぐると非常にたくさん解説が出てくるのだが、以下の図のように、作成したsshトンネルの入り口を仮想的にターゲットのサーバのようにみたてて使いたい場合、ぐぐってもあまり出てこない留意事項があるのでメモ。

「ローカルPC」から「乗り込み先」に tcp 443 (SSL)で接続したいのだが、「ローカルPC」上で tcp 443 が他アプリに使われているとか、複数人で共有したいため、sshトンネルの入り口は「踏み台(自拠点)」に開設したいということである。

ぐぐって出てくる一般的な解説では、上記のトンネル#1を開設する際に ssh に指定するパラメータは、

  -L 443:10.0.0.123:65443

ということになっている。(65443 は例)

しかしこれだと、図の「踏み台(自拠点)」マシン上で、 127.0.0.1:443 (tcp) で LISTEN 状態のTCPソケットが作成されてしまい、図の「ローカルPC」から接続できない。

さて、man ssh して -L の説明を読むと、こんなことが書いてある。

     -L [bind_address:]port:host:hostport

             Specifies that the given port on the local (client) host is to be
             forwarded to the given host and port on the remote side.  This
             works by allocating a socket to listen to port on the local side,
             optionally bound to the specified bind_address.  Whenever a con-
             nection is made to this port, the connection is forwarded over
             the secure channel, and a connection is made to host port
             hostport from the remote machine.  Port forwardings can also be
             specified in the configuration file.  IPv6 addresses can be spec-
             ified by enclosing the address in square brackets.  Only the
             superuser can forward privileged ports.  By default, the local
             port is bound in accordance with the GatewayPorts setting.  How-
             ever, an explicit bind_address may be used to bind the connection
             to a specific address.  The bind_address of ``localhost'' indi-
             cates that the listening port be bound for local use only, while
             an empty address or '*' indicates that the port should be avail-
             able from all interfaces.

赤字で強調した(省略可能な) [bind_address:] のところがポイントで、図のように使いたい場合は

  -L 0.0.0.0:443:10.0.0.123:65443

と、bind する IP address を明示的に指定してやる必要がある。
0.0.0.0 は言うまでもなく INADDR_ANY で、任意のIP addressにマッチする。
図の「踏み台(自拠点)」が複数のNICを持っていて、特定の IP に制限したい場合は、

  -L 192.168.100.2:443:10.0.0.123:65443

等と、適切な unicast IP address を書くこと。

さて、話はまだ続く。

     -L [bind_address:]port:host:hostport

の赤字強調した2番目の host には、一般的には接続先の IP address を書くと解説されているし、実際、man page の説明もそう読める。

しかし、ここはどんな IP address を書いても無視され、コマンドラインとしては

  $ ssh   -L [bind_address:]port:host:hostport    user@remote_host

と指定した時の remote_host (図のトンネル#1では「踏み台(他拠点)」のインターネット側IP addressに対応)が使われる。(ので、実は、どんな IP address を書いてもかまわない)

# Apr. 27, 2013 追記 begin

上記の記述に誤りがありました。
この記事では、


  $ ssh   -L [bind_address:]port:destination_host:hostport    user@remote_host

と記述した場合の destination_host と remote_host が同じサーバである場合を想定していました。
なので、この場合に限っては上に書いたとおりになるのですが、remote_host に中継させて、
さらに remote_host から IP reachable な別の destination_host に対して forwarding させることも
できます(というか、本来の SSH port forwarding の趣旨はこちらになります)
ですので、「さて、話はまだ続く」以下は間違っています。
destination_host の指定値には、とても重要な意味があります。

訂正してお詫びいたします...
# Apr. 27, 2013 追記 end





いや、紛らわしいですね...

Monday, January 7, 2013

ssh tunnel 越しに vSphere Client 接続する

昨年、こんな記事(http://thatsdone-j.blogspot.jp/2012/12/windows-netstat-ps.html)を書いたのだが、肝心の冒頭の件をまとめていなかったのでメモ。

いろんな案件で作業していると、多段の踏み台を経由しないと乗り込めない環境をあてがわれることも多い。もっと具体的には、自分の手元から IP reachable ではないが、ssh tunnel なら多段に張れないこともない…というような状況。

たぶん、FAQに近いような話だと思うのだが、そういう奥まったところで ESX/ESXi が動いている場合、どうやって vSphere Client で接続しようか?という話になる。

答は簡単で、
  1. tcp 443 -- 制御用
  2. tcp 902 -- VMのコンソール接続用
の2つのポートを ssh トンネルでつないでやればいい。
VMのコンソールをとる気がなければ tcp 443 だけでもOK。

ところで、ESXi に向かってどうやって ssh tunnel をはるか?

これも簡単で、管理用の ESXi shell を有効 + ssh を有効にしておいて、ssh で remote login できるようにしておくだけでOK。
ESXi shell 環境に向かって、tcp 443/tcp 902 の ssh tunnel を張っておけば vSphere Client でアクセスできるようになる。

Saturday, January 5, 2013

VMware Player での仮想ネットワークに関するあれこれ

手元での各種の作業に VMware Player を使っている人は多いと思う。

私は、最新の 5.0系より1つ古い 4.0.4 というバージョンを使っているのだが、
最近まで知らなかったことがあったのでメモ。

(1) 仮想ネットワークに nat を使っている場合にも static にIPを割りつけたい
 (たぶんこっちはFAQレベル)

 言うまでもなく、VMware (Player/Workstation等)の仮想ネットワークのNATでは、
 内蔵DHCPサーバからprivate IPをもらうことができ、VMからNATで外に出ていくことができる。

 ただ、いろいろいじっていると、VMに固定IPを割りつけたいこともよくある。
 VMware の内蔵DHCPサーバが覚えていて、同じIPを割り振ってくれることも多いのだが、
 何台もVMを作って起動・停止を繰り返していると、必ずしも必ず固定というわけにはいかない。

 単純には、一度内蔵DHCPから払いだされたIPをそのまま static に定義してしまえ…という
 乱暴な解決策が思いつくが、これはうまくいかない。NATで認識してくれない上に、
 ホスト側からも接続できなくなる。

 答は単純(…たぶんFAQで自分が知らなかっただけな気がする)で、
 内蔵DHCPサーバが払いだすIPのレンジは、NATで使えるIPのレンジのほぼ半分で、
 (通常は /24 なので第4オクテットホスト部が 129 以上の範囲から払いだされ、
 128以下のうち 1 (ホスト用) と 2 (NAT gateway用)は予約で、これら以外はゲストOS上で
 static に設定すれば普通にホストとの直接通信も、NAT経由の外部通信も可能になる。

 なお、根拠については、以下(の、特に p179 あたり)くらいしか見つからなかったのだが、

 http://www.vmware.com/jp/pdf/server_vm_manual.pdf
 
 このへんの仕様は不変だと思われる。
 (し、次の vmnetcfg の出力を見ても大丈夫だと思われる)


(2) 仮想ネットワークの設定をいじりたい

(2-1) 仮想ネットワーク設定操作用のツール(vmnetcfg)を追加インストールする

2.x系くらいの古いVMware Player の時代には、仮想ネットワークエディタというものが
標準でついてきていた。少なくとも私が使っている 4.0.4 ではインストールされないのだが、
実は配布アーカイブには同梱されており、追加インストール可能である。


情報源はこのへん↓(ぐぐると日本語でもそれなりに記事が出てくるようだ)

 http://communities.vmware.com/message/1853079


以下が手順。
  1. VMware Player の配布アーカイブを -e オプション付きで起動し、中身を取り出す

    C:\tmp>VMware-player-4.0.4-744019.exe -e c:\tmp\vmwp

    -e には展開先のフォルダを指定する。
  2. 出てきた network.cab に含まれる vmnetcfg.exe を取り出す
    C:\tmp>dir vmwp
     [略]
    2013/01/05  15:17    <DIR>          .
    2013/01/05  15:17    <DIR>          ..
     [略]
    2013/01/05  15:17         1,486,370 micros~2.cab
    2013/01/05  15:17           589,824 module_core.dll
    2013/01/05  15:17           356,352 module_ws.dll
    2013/01/05  15:17           216,071 nat.cab
    2013/01/05  15:17           207,483 net32.cab
    2013/01/05  15:17           173,955 net64.cab
    2013/01/05  15:16         2,855,112 network.cab  ★この cab をひらいて中身を取り出す
    2013/01/05  15:17        19,262,287 ovftoo~1.cab
    2013/01/05  15:17        15,132,466 ovftoo~2.cab
     [略]
                  48 個のファイル         242,418,155 バイト
                   2 個のディレクトリ  23,789,588,480 バイトの空き領域
  3. vmnetcfg.exe を VMware Player のインストールディレクトリにコピーする
    私の場合は以下。

    C:\Program Files (x86)\VMware\VMware Player

    VMware Player のインストールディレクトリにコピーせずに vmnetcfg.exe を単独で
    起動すると「sigc-2.0.dll が存在しない」という趣旨のエラーが出るので注意のこと。

(2-2) 仮想ネットワーク設定を変更する。

 以下のような画面がでてくれば(2-1)のインストール作業は正解である。
 あとは見てわかるとおりで、例えば、NATで使うIPの network address を変更するなど、
 わりと細かい設定変更も可能である。


 下段右のほうの「DHCP設定(C)」をクリックして出てくるダイアログが以下で、


 前半で説明した、DHCPで払いだす IP address のプールの指定(等)を変更できることがわかる。