Hatena::ブログ(Diary)

(ひ)メモ このページをアンテナに追加 RSSフィード

2012-08-22 (Wed)

同じサブネットへのNIC 2枚指し、またはソースルーティングのおはなし

「NIC 2枚刺し」というと「IP masqueradeを使ってLinuxでルーターを作ろう!」的な話を思い出す老害です。こんにちは。

NICを2枚生やしたサーバーから同じサブネットに両方の足をのばす機会があったのですが、じゃっかん躓いたのでそのメモです。

具体的にいうと、eth0の方は問題ないのですが、eth1についているIPアドレスへの疎通ができない、というものでした。

以下、

という体で読んでください。


さて、

別サーバーからpingしつつ、eth1でtcpdumpしてみると、echo requestは届いているのが観測できました。が、echo replyを返していません。

# tcpdump -i eth1 -nl icmp
listening on eth1, link-type EN10MB (Ethernet), capture size 96 bytes
15:19:07.469577 IP 10.0.0.100 > 10.0.0.11: ICMP echo request, id 55821, seq 551, length 64
15:19:08.469517 IP 10.0.0.100 > 10.0.0.11: ICMP echo request, id 55821, seq 552, length 64
15:19:09.469253 IP 10.0.0.100 > 10.0.0.11: ICMP echo request, id 55821, seq 553, length 64

同じようにeth0でtcpdumpしてみると、入ってきたeth1じゃなくて、eth0からecho replyを出しているのが観測できました。

# tcpdump -i eth0 -nl icmp
listening on eth0, link-type EN10MB (Ethernet), capture size 96 bytes
15:22:14.481126 IP 10.0.0.11 > 10.0.0.100: ICMP echo reply, id 55821, seq 738, length 64
15:22:15.480946 IP 10.0.0.11 > 10.0.0.100: ICMP echo reply, id 55821, seq 739, length 64
15:22:16.480895 IP 10.0.0.11 > 10.0.0.100: ICMP echo reply, id 55821, seq 740, length 64

なので、10.0.0.11宛のパケットは入ってきたeth1から出ていくようにすればOKそうです。

これをハンドリングするにはソースルーティングの設定をすればよくて、Linuxではiproute2の出番になります。

古来のrouteコマンドですと、宛先に応じてNICのデバイスやnext hop routerの指定を行いますが、Linuxではこのテーブルを複数持つことができ、さまざまな条件でどのテーブルを参照させるかを指定することができます。

「さまざまな条件」とは、例えば

  • 送信元IPアドレス
  • パケットが入ってきたデバイス名
  • fwmark

といったものです。fwmarkとは、iptables(試したことはないですがebtablesでもできると思います)で--set-markで印をつけたパケットをひっかけるためのもので、iptablesの世界の柔軟なルールを使ってパケットにマーキングをし、それに応じてルーティングまでも切り替えられるというかなり(いい意味で)変態なものです。


話を元に戻します。

まず、なぜeth1から来たパケットがeth0から出ていくのか、iproute2のコマンドを使ってrule tableやroutingの情報を確認してみます。

rule tableはip ruleコマンドで確認できます。

# ip rule show
0:      from all lookup 255
32766:  from all lookup main
32767:  from all lookup default

左の数値はruleの優先順位で、数値の小さい順に参照されます。

from allはこのrule内のrouteを参照するかどうかの条件です。

lookupのあとの255かmainがrule tableのIDです。基本的にIDは数値なのですが、/etc/iproute2/rt_tablesにIDと文字列の対応を書いておく(/etc/hostsやservicesの様なものです)と、文字列で表示されるようになります。

255のrule tableはループバックやブロードキャストのルーティングが定義されています。defaultはどのtableのroutingにもマッチしなかった場合に参照されるtableですが、多分中身は空だと思います。

で、mainが、いつもnetstat -nrやroute -nで見ているルーティングが定義されているtableです。ipコマンドでruleの中のルーティングを確認するには、ip routeコマンドを使います。netstat -nrと比較してみたり、255やdefault tableも見てみるといいと思います。

# ip route show table main
10.0.0.0/18 dev eth0  proto kernel  scope link  src 10.0.0.10
169.254.0.0/16 dev eth0  scope link
default via 10.0.0.1 dev eth0

さて、10.0.0.11宛のパケットは、優先順位的に最初の255 tableの中のルーティングにはマッチしないので、続いてこのmain rule tableの中に入っていくわけですが、最初のルーティングルールにマッチし、そこには「dev eth0」とあるのでeth0から返りのパケットが出ていく、というあんばいなのがみてとれます。


というわけで、

  • mainより優先順位が高いrule tableで、
  • eth1から出ていくようなルーティングを定義

すればよさそうです。

rule tableの新規追加はip ruleコマンドでやります。

今回は、mainより優先ということで優先度200、tableのIDは100で、出るパケットの送信元アドレスがeth1の10.0.0.11のをひっかけるようなtableを作ります。

# ip rule add from 10.0.0.11 table 100 prio 200

そしてこのtableの中に、eth1から出ていくようなルーティングをip routeコマンドで定義します。

# ip route add dev eth1 src 10.0.0.11 table 100

これで10.0.0.11(eth1)宛のパケットもちゃんと返せるようになります。

ちなみに、どのrouteで出て行くか確認するには、ip route get IPADDRESS すればわかります。

落穂ひろい

今回はid 100というrule tableを作りました。途中でも触れましたが、/etc/iproute2/rt_tables に

100  ENI

とか書いておくと、ip rule showで数値でなく文字列(ENI)で表示されるので、わかりやすい名前を与えておくといいと思います。


ipコマンドのサブコマンドは特定できる文字まで省略できます。

例えば、ip route show table mainは、ip ro s t mainと書くこともできます。

この例はちょっとアレですが、ifconfig -a相当の情報はip addrで表示できるのですが、ip aと打つのはよくやります。

参考文献

はてなユーザーのみコメントできます。はてなへログインもしくは新規登録をおこなってください。

2003 | 11 | 12 |
2004 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 10 | 11 | 12 |
2005 | 01 | 02 | 03 | 05 | 08 | 09 | 10 | 11 | 12 |
2006 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 12 |
2012 | 01 | 02 | 03 | 06 | 08 | 10 | 11 | 12 |
2013 | 01 | 02 | 03 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2014 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 10 |
2015 | 01 | 02 | 07 | 10 |
2016 | 01 | 05 | 10 | 12 |