Home > Archives > 2010-08

2010-08

DSRとは

DSRとは

Direct Server Returnのことです。一般にはNAT(Network Address Translation)との対称みたいな感じで使われていることが多い気がします。先ほどの例であった同一IP帯内でのDNAT戻りパケットの処理を少し変えた感じです。

・DSRの例

「クライアント(192.168.0.10:5000)」→(192.168.0.20:80あて)→「DSRサーバー(受付:192.168.0.20)(宛先IPは書き換えず、パケットの送付先のみ変更。192.168.0.30のNICあて)」→「192.168.0.30:80」

上記例は、先ほどのDNATとほとんど同じです。ただし、今回は、192.168.0.30に届くパケットの送信先は192.168.0.20のままです。このパケットが192.168.0.30に届くのは、パケットの宛先MACアドレスのみが、192.168.0.30のMACアドレスに書き換わっているからです。ゲートウェイにIPパケット送るときと同じです。

(MACアドレスとパケットについて)通常のTCP/IP通信では、次のようになっています。(それぞれの部分でパケットを一定サイズに分割しています。)

  「アプリケーションが送りたいデータ」→「TCPパケットで包み込む(ポート番号付加)」→「IPパケットで包み込む(送信/受信IPアドレス付加)」→「ethernetフレームで包み込む(宛先/送信元MACアドレス付加)」→「ネットワーク上を流れる」

もちろん、届いたパケットは逆順で元に戻されてデータとなります。(TCPの輻輳処理は省略)上記のDSR例のように送信先が異なっていても、パケットが届くのは、ethernetフレームでのMACアドレスが(192.168.0.30)のMACアドレスに設定されていたためです。

 話を戻しまして、通常であれば、DSRのパケットは、(192.168.0.30)では処理されません。当然、IPアドレスが自分のIPでないためです。iptablesとかで、Forwarding処理を許可していれば、(192.168.0.30)に転送してしまうかもしれません。(かもです。ARPチェックではねられるのかな?誰か教えてください。)

 DSRを行うには、このパケットを受け取れるようにしなければなりません。最も簡単な手段が、「透過型プロキシ設定」を行うことです。透過型プロキシを利用すると、自分のIPで無いIPアドレスのデータを受け取って、返信を、あたかもそのIPアドレスからのように返すことができます。これを行うのは、非常に簡単で、iptablesで次のように設定するだけです。

{{{

# iptables -t nat -A PREROUTING -d *.*.*.*(受け取りたいIP) -j REDIRECT

}}}

詳しい説明は省略しますが、REDIRECTターゲットを使うと、自分自身のIPアドレスにリダイレクトして、その結果を返すときは、もともと来たIPアドレスに書き換える処理をする、という動作をしてくれます。まんま「透過型プロキシ」ですね。

iptablesにこの動作を加えることによって次のような流れができあがります。

・DSRの例

「クライアント(192.168.0.10:5000)」→

→(元:192.168.0.10:5000、先:192.168.0.20:80)→

→「DSRサーバー(受付:192.168.0.20)(宛先IPは書き換えず、パケットの送付先のみ変更。192.168.0.30のNICあて)」

→(元:192.168.0.10:5000、先:192.168.0.20:80 ※送信先MACアドレスは192.168.0.30のNIC)

→「192.168.0.30のiptablesが、192.168.0.20あてのパケットを受け取って192.168.0.30:80にリダイレクト」

→(元:192.168.0.10:5000、先:192.168.0.30:80)→

→「192.168.0.30:80で待ち受けているアプリが処理して返答」

→(元:192.168.0.30:80、先:192.168.0.10:5000)→

→「192.168.0.30のiptablesが送信元を192.168.0.20に書き換えて192.168.0.10:5000に返信」

→(元:192.168.0.20:80、先:192.168.0.10:5000)→

→「クライアント(192.168.0.10:5000)が受信」

こんな感じの流れになります。略すと

[クライアント]→[DSRサーバー]→[バックエンドサーバー]→[クライアント]

となり、行きはDSRサーバーを通るが、戻りは直接返す、という行動になります。このため、DSR(Direct Server Return)というみたいです。

DSRの利点は、DSRをロードバランサと置き換えると、わかりやすくなります。

 「ロードバランサは、リクエストをバックエンドに分配はするが、返答はバックエンドが直接行う。このため、ロードバランサは返答の処理の必要性が無くなり、処理が軽くなる。

いいですね〜★。帯域も無駄遣いしなくて済みますし。

※ ふつうのロードバランサは、大抵次のような行動をします。(NATのところで少し触れましたが・・)

[クライアント]→[ロードバランサ]→[バックエンドサーバー]→[ロードバランサ]→[クライアント]

この動作を行うため、ロードバランサは、バックエンドとの通信時に送信元と送信先のIPをどちらも替えています。

次は、実践編。keepalived使って、DSRでmysqlの負荷分散します。

間違いや誤植がありましたら、お教えください。

NATとは

NATとは

Network Address Translationのことです。発信元(ソース)IPや、送信先(ディスティネーション)IPといったネットワークアドレスを変換します。発信元IPを変換するものをSNAT、送信先IPを変換するものをDNATと呼びます。まず、SNATの例ですが、次のようになります。

・SNATの例

「クライアント(192.168.0.10:5000)」→(123.4.5.6:80あて)→「NATサーバー(GW)(受付:192.168.0.1、GIP:111.123.123.*)(ソースIP書き換え111.123.123.*:5000)」→「123.4.5.6:80」

SNATでは、上記のように、NATサーバーが、ソースIP(発信元IP)を書き換えます。リクエスト先の(123.4.5.6:80)からは、(111.123.123.*:5000)からのアクセスに見えます。よって、リクエスト応答は(111.123.123.*:5000)に返します。NATサーバーは、このポートに返ってきたパケットの宛先IPは、(192.168.0.10:5000)であると記憶しているので、宛先IPを(192.168.0.10:5000)に替えてクライアントに送ります。

このようにして、IPアドレスの書き換え操作のみで、アドレス帯の異なるネットワークと外向けIPひとつで通信できるようになります。

ただし、単にIPアドレスだけを書き換えると問題が発生する場合があります。例えば、上記の例の通信が行われている最中に、クライアント2から、同じ5000番ポートからアクセスが来た場合、NATサーバーは、IPアドレスのみの書き換えを行っていると、(111.123.123.*:5000)宛に戻ってきたパケットをどちらのクライアントに送ればいいのかわからなくなってしまいます。このようなことが起こらないように、port番号も変更する(クライアント2はport:5001を使おう!みたいな感じ。)ものを、「IPマスカレード」といいます。ふつう、natというと、IPマスカレードのことを言うことが多いようです。(この機能は、家庭のブロードバンドルーターとかに標準で入っています。この機能のおかげで、複数台のPCがインターネットに接続できます。)

次に、DNATですが、良く使われる例として、「家庭でサーバー立ち上げたい」ときに使います。

・DNATの例

「クライアント(123.4.5.6:5000)」→(111.123.123.*:80あて)→「NATサーバー(GW)(受付:111.123.123.*:80、内部IP192.168.0.1)(宛先IP書き換え192.168.0.10:80)」→「バックエンドサーバー192.168.0.10:80」

こんな感じで、外部からのアクセスが来た場合、宛先IPを書き換えて、内部のサーバーに投げるときに使えます。バックエンドサーバーは、送信元(123.4.5.6:5000)から来たパケットとして処理を行い、戻りパケットは、ゲートウェイであるNATサーバーに送り、NATサーバーが、送信元IPを書き戻してクライアントに送ります。

 「未知のIP帯→既知のIP帯」:DNAT

 「既知のIP帯→未知のIP帯」:SNAT

みたいな感じです。IPv4のグローバルIPが枯渇してきたために考えられたものですが、よくできていますね。

NATの問題点

NATは万能ではありません。例えば、「既知のIP帯→既知のIP帯(同一IP帯)」で、NATを使用すると、問題が発生します。次の例は、サブネットマスク255.255.255.0で考えてください。

・DNATの例(問題発生)

「クライアント(192.168.0.10:5000)」→(192.168.0.20:80あて)→「NATサーバー(受付:192.168.0.20)(宛先IP書き換え192.168.0.30:5000)」→「192.168.0.30:80」

上記例のように、NATサーバーによって、宛先IPアドレスを書き換えて別のサーバーに転送しています。「こんな必要あるのか?」と思われた方、ときどきあります。特に、サーバー周りですが。

さて、上記のようなDNATに何の問題があるのでしょうか。送信は問題無く行われるのですが、問題は、戻りパケットの方にあります。宛先である「192.168.0.30:80」では、パケットは次のような形になっているはずです。

  「送信元:192.168.0.10:5000、宛先:192.168.0.30:80」

このパケットを返信すると、「送信元:192.168.0.30:80、宛先:192.168.0.10:5000」となります。送信元は、送信先が同一アドレス帯であるので、そのままパケットを宛先に送ります。NATサーバーには返しません。

 このパケットを受け取ったクライアントPCは、「送信元:192.168.0.10:5000、宛先:192.168.0.20:80」で送ったパケットの返答が、(192.168.0.30)と、異なるアドレスから返ってきたので、受け取りを拒否します。(というよりも、そもそも返答と気付きません。)

このように、パケットを何度送信しても、戻ってこないことになり、通信が成立しません。

 また、SNATは同一IP帯では、成立しません。(そもそも初めのパケットが、NATサーバーに届かないため。)

 上記のDNAT問題を解決するパターンは、2つあり、1つはリバースプロキシやロードバランサ等の転送で行われることがある、宛先も送信元も同時に書き換える(パケット自体作り替えるとか・・)です。また、もうひとつが、DSR構成です。

DSRは次回・・

間違いや誤植がありましたら、お教えください。

透過型プロキシとは

iptablesを利用して、透過型プロキシなるものを使って、DSR構成を組んでみました。

その前に、プロキシとかDSRとかって何?みたいなことを簡単にまとめました。

プロキシ・リバースプロキシ・透過型プロキシとは

 プロキシ(代理応答)は、例えばインターネットにアクセスする際に、クライアントPCから直接リクエストを投げるのではなく、一旦別のサーバーにリクエストを投げ、リクエストを受け取ったサーバーが代理でインターネット上のホストにアクセスするといった行動のことです。良く使われる例としては、「グローバルIPが一個しかないけれど、複数のPCからインターネットに接続したい」といったとき、プロキシサーバーを立てて、代理応答させる等に使います。(natでも同様のことを実現できますが、プロキシを使うと、プロキシサーバーにキャッシュさせて応答を高速化したり、プロキシサーバーでアクセス制限とかもできます。natはレイヤ4でアドレス変換するだけなのに対し、プロキシはレイヤ7での行動ができるという感じでしょうか。)

 また、リバースプロキシは、例えばHTTPサーバーを立てている際に使います。(クライアント側でなく、サーバー側。)サーバーあてに来たリクエストを、そのURLとかによってバックエンドサーバーに分配する役目をします。同一URLに来たアクセスをバックエンドに分配するといったもの(この場合、どういった理由で分配するというものが不明確なので、リバースプロキシの役目とは異なります。)はロードバランサで実現します。

 透過型プロキシとは、上記ふたつとは少々異なっていて(これまではレイヤ7での動作が主。)、レイヤ4での動作が主になります。具体的には、IPアドレス自体は自分あてで無いものを、自分宛に書き換えて動作させるといったことを行います。

 「クライアント(192.168.0.10)」 →(リクエスト:123.1.2.3:80あて)→ 「透過型プロキシサーバー(192.168.0.1)のレイヤ4(IP書き換え)」→「透過型プロキシサーバーのレイヤ7(192.168.0.1:80)」

みたいな感じの動作をします。もちろん、戻りパケットは

 「クライアント(192.168.0.10)」 ←(リクエスト:123.1.2.3:80から)← 「透過型プロキシサーバー(192.168.0.1)のレイヤ4(IP書き換え)」←「透過型プロキシサーバーのレイヤ7(192.168.0.1:80)」

と動きます。注意しなければならないのは、

 ・パケットが正しく透過型プロキシに届くようになっているかどうか(よって、普通はゲートウェイ等にします。)

 ・アプリケーションの設定だけでは、動かない。(Linuxでは、iptablesとかの助けが必要。)

となります。

透過型プロキシを使った例としては、

1.クライアントPCのプロキシ設定をせずに、プロキシサーバーがグローバルIPを全部受け取れる(IP書き換えできる)状態にしておけば、クライアントからは、グローバルIPに直接接続しているように見えるが、実際はプロキシサーバーを通っている。

とか、

2.自分とは異なるIPアドレスあてのパケットを取得して、処理し、他のIPのマシンになりすましてパケットを返信する。

といったことがあります。

つぎはNATについてです。

間違いや誤植がありましたら、お教えください。

Linuxで帯域監視

テストでちょっとサイズの大きいデータを沢山扱うサーバーを複数台作成しなければならなかったので、それぞれのサーバーでコネクションあたりの帯域を制限して、「各サーバのNICの帯域監視」を行って、空いているサーバーに振り分けよう!ということになりました。

さて、Linuxでネットワークを経由しての帯域監視をするには・・・あれ?あんまりいいソフトないな。SNMPとかはあるのですが、UDPだから必要なときに確実にデータとるにはちょっと不安だし・・・、sshでつないでゴニョゴニョするのは無意味な転送が多すぎるから、毎秒(または数秒おき)やるのはちょっと・・。

「欲しいのはTCP接続で、/proc/net/devのデータの差を単純に取得したい、しかも余計な転送量喰わない軽いアプリ」なんですが、そんな都合のいいものがみつかりませんでした。

そんな訳で簡単な帯域計測サーバーをつくってみました。次のような仕様です。

「監視したいサーバーで帯域計測サーバーをデーモン起動」

「監視側からアクセスしたら直近の転送量(/sec)が返ってくる」

これだけ。結構あっさりできました。

走らせてみて気付いたのですが、監視側からサーバー接続を1秒おきに繰り返させて、サーバー側でnetstat・・・・

うわ、TIME_WAITが山ほどいる・・

・・当然ですね、TCPだし。

LInuxはTCPコネクション開放が60秒後なので、毎秒やったら、TIME_WAITが60個たまる訳です。TCPの仕様上当然といえば当然なのですが、

無駄なので消す方法ないですかね〜。誰か知っている方いらっしゃったら教えてください。

もし、同様なものをお探しな方いらっしゃいましたら、コメントいれといてください。ソース公開します。適当すぎて怒られそうですが・・

ちなみに検証環境はRHEL5、CentOS5(ほとんど一緒ですね)、開発言語はCです。

「〜」は2つある!?

文字コードセットutf-8で開発を行っていたところ、見た目はまったく同じなのに、何故かstrcmpとか正規表現マッチとか試してみても絶対通らないという現象がおこりました。次のような文字列です。

1.「こんにちは〜開発からのお知らせ〜」

2.「こんにちは〜開発からのお知らせ〜」

理由がわからず、2時間ほど悪戦苦闘・・・・。まさかとは思いながら16進数で表示して全部チェックすると、

あれれ

なんか違う・・・

まさか、見た目は同じなのに文字コードが違う??文字コードセットはutf-8に変換しているのに・・

というわけで、一文字ずつ調べていくと、「〜」の文字コードが、0xEFBD9Eと0xE3809Cと異なっていることがわかりました。

ググると、

0xEFBD9E:全角チルダ(表示は「〜」)

0xE3809C:波ダッシュ(表示は「〜」)

らしいです。見た目は同じです。

なぜこのような現象が起こったのかチェックしていくと次のようなことがわかりました。

Windows:日本語の標準文字コード(cp932:いわゆるshift-jisがベース)には、波ダッシュなるものはそもそも存在しない。「〜」=全角チルダ。よって、utf-8のファイルをwinで編集すると0xEFBD9Eで保存される。

Mac:日本語の標準文字コードはshift-jis系のようだが、ことえりはiso-2022-jp寄りっぽい。「〜」=波ダッシュ。よって、utf-8のファイルをmacで編集すると0xE3809Cで保存される。

がーん。同じutf-8なのに、winで打った文字とmacで打った文字は文字コードが異なるなんて。

また、winで作った文字列(全角チルダ)をメールの文章に入れてphpでメール送信を行うと、utf-8 → iso-2022-jp → utf-8の過程で、全角チルダが波ダッシュに変更されてしまうことがわかりました。iso-2022-jpにはどちらもあるようですが、phpのmbstringの変換表で波ダッシュに変換されているようです。(*正確かどうかの検証は行っていません。現象から判断しました。実際のところがどのような理屈か知ってらっしゃる方がいたら、ぜひ教えてください。)

結構有名な話のようですが、初めて知りました。全角ってやっかいだ・・

Home > Archives > 2010-08

Search
Feeds

Return to page top