受け取ったUDPパケットのデスティネーションアドレスを知る方法

マルチホームホストなどで複数のアドレスが振られている場合に、受け取ったパケットがどのアドレス宛てのものなのかを知りたい場合がある。 ソケットAPIのrecvfrom(2)では、パケットを送出した側のソースアドレスを知ることはできても、相手がどのアドレスに送ってきたのかを知ることはできない。 TCPならばaccept()後にgetsockname()で調べることができるけれども、はて、UDPではどうしたらいいのか(おまけ:TCPでもaccept前に知りたい場合があるよね)、というお話。
8
AoiMoe a.k.aしお兄P @AoiMoe

recvfrom()には若干欠点があって、peerのアドレスは分かってもローカル側のアドレスが分からない。複数のアドレスが付いているマシンで、どのアドレスのどのポート宛てに来たのかを知りたいっていう需要は無くもないはずなのだが。

2011-06-30 19:20:46
AoiMoe a.k.aしお兄P @AoiMoe

それを知りたい場合には、一つのソケットにINADDR_ANYでbind()するんじゃなくて、アドレスの数だけソケットを作ってひとつずつbind()するという方法はある。

2011-06-30 19:23:36
AoiMoe a.k.aしお兄P @AoiMoe

しかし、今までrecvpair(2)みたいなものを作ろうと考えた人はいないんだろうか

2011-06-30 19:41:42
Takanori Watanabe 💉💉💉💉💉 @takawata19

それこそ、setsockopt+recvmsgという一番汎用的なものがあるし!

2011-06-30 19:44:02
SODA Noriyuki @n_soda

@AoiMoe @takawata さんが書いてるけど、IP_RECVDSTADDRつうのが。ただしLinuxだと代わりにIP_PKTINFOを使うらしい。Solarisは昔はIP_RECVDSTADDRだけだったんだけど、今はIP_PKTINFOもあるみたい。

2011-06-30 20:02:56
SODA Noriyuki @n_soda

@n_soda @AoiMoe @takawata19 しまった、「19」を書き忘れた。失礼しますた。_o_

2011-06-30 20:13:46
SODA Noriyuki @n_soda

とはいうものの、自分のプログラムでは、複数のソケット使ってます>UDP受信の宛先アドレス/UDP送信アドレス問題。どうせaccept(2)との両面待ちでselectしてるとこなので問題ないせいもあるけど。

2011-06-30 20:32:15
ryo @rsh

@n_soda @AoiMoe @takawata IPv6に関してはRFC3542でAPIがまとめられてるんですが、IPv4はOS依存でバラバラなのです。IPv4もv6にならって送受信時ともにIP_PKTINFOで統一すべきですよね…

2011-06-30 20:17:10
ryo @rsh

@n_soda @AoiMoe @takawata あぁ、正確には、受信時はIP_RECVDSTADDR、送信時はIP_PKTINFO、です。

2011-06-30 20:19:26
ryo @rsh

@n_soda @AoiMoe @takawata だあああああああ、間違った。。受信時はIP_RECVPKTINFO、送信時はIP_PKTINFO、です…。死んできます。

2011-06-30 20:22:06
ryo @rsh

ちなみにNetBSDでは送信時にbindaddr/bindportを指定する方法が無いので動きません(ぉ

2011-06-30 20:40:06
AoiMoe a.k.aしお兄P @AoiMoe

そうか ip(4) を見るのが正解だったか

2011-06-30 20:18:52
AoiMoe a.k.aしお兄P @AoiMoe

まあWinSockを使ってる俺には関係ないんだがな!

2011-06-30 20:19:57
SODA Noriyuki @n_soda

@AoiMoe ぐぐってみると、WinXP以降はあるみたい(IP_PKTINFO): http://t.co/UjK9RVF

2011-06-30 20:22:29
AoiMoe a.k.aしお兄P @AoiMoe

俺のPSDKドキュメントが古かっただけか!

2011-06-30 20:28:55
AoiMoe a.k.aしお兄P @AoiMoe

platform sdk の include を grep したらちゃんとあるのにドキュメントに書いてねえ

2011-06-30 20:33:13

(複数socketを使ってbindする手法の問題点)

ryo @rsh

@AoiMoe @n_soda @takawata19 一つ忘れてましたが、宛先アドレス毎にsocket作って多面待ちでacceptする方法だと、アドレス付け替えられた時に動かなくなるので真面目にやるとbindやntpのようにルーティングソケット監視する必要があるんですよね。

2011-07-01 15:15:01
SODA Noriyuki @n_soda

@rsh @AoiMoe @takawata19 ウウム、それは面倒ですね。NetBSDでも動かそうとすると、受信はIP_RECVDSTADDRして、送信時はまだbindしてなければbnidする方が簡単?

2011-07-01 15:30:53
ryo @rsh

@n_soda @AoiMoe @takawata19 その方法だと、送ろうとするsocketでbindした瞬間に相手からパケットが来たら、そのsocketで受信しちゃう問題があるのです ;-)

2011-07-01 15:33:38
SODA Noriyuki @n_soda

@rsh @AoiMoe @takawata19 ガビーン。ルーティングソケット監視めどいです。そのソケットで受信してもちゃんと動くようにしておけばいいのかしら。アドレスが変わる前提だと、bindしたソケットを捨てるタイミングが悩ましいなあ。毎回捨てるのも勿体ない気が…

2011-07-01 15:40:56
ryo @rsh

@n_soda @AoiMoe @takawata19 受信してcloseするまでをatomicにできない以上どうしようもない気が。ルーティングメッセージ監視するか、NetBSDにもIP_PKTINFOを導入しましょう!!

2011-07-01 15:43:40
SODA Noriyuki @n_soda

@rsh @AoiMoe @takawata19 non-block readして何もなければclose、raceはあるけど、それは再送で対処してもらう…で、実用上はまあOKな気が。駄目かな?気合があればルーティング監視の方が勿論いいですね。IP_PKTINFO導入は賛成です。

2011-07-01 15:55:55