異なるネットワークセグメントにあるPS3からDLNAサーバにアクセスしようとしてうまく行かなかった話
- 公開日: 2020/06/20(土) 12:39[JST]
- 更新日: 2020/06/20(土) 13:48[JST]
ラズパイの後ろ(有線LAN側)にプレステ3(と15年前の最初期のフルHDテレビ。D端子のみでHDMI無し)を設置して、手前(無線LAN側)にあるDLNAサーバにアクセスできないかとやってみて結局できなかったのでメモ。
UPnPの仕組み
nabeの雑記帳の「UPnP/SSDPマルチキャスト中継プログラム(DLNA用)」によれば以下の通り。
クライアントは239.255.255.250:1900のUDPパケットを出力する。これはマルチキャストアドレスで同一ネットワークセグメントにある全てのホストに送られる。
UDPパケットを受け取ったサーバは、送信元ポート1900のパケットをクライアントに送り返す。このパケットには、クライアントがサーバにアクセスするための情報を記したURLが含まれている。
クライアントは上記URLに記載の情報に基づいてサーバにアクセスする。
基本的にはマルチキャストパケットはルータを超えられない(=UPnPは同一ネットワーク内での機器同士のやり取りであることを前提としている)のでサーバとクライアントとの間にルータがあるとうまく行かない。
試み(1)ルータにルーティングテーブルを設定してみる
まずは単純に「マルチキャストなパケットをサーバ側に通過させるようルーティングテーブルを設定すればいいんじゃない?」と思い、 sudo route add -net 239.0.0.0 netmask 255.0.0.0 wlan0 を実行してみた。が、PS3はサーバを認識してくれない。サーバ側tcpdumpを取ってみたが、パケットがPS3から来た気配はない。
試み(2)ルータにパケットの再送出をやってもらう
上記のnabeの雑記帳に掲載されているperlコードを実行させてみた。ただ、掲載されているコードのままだとうまく動いてくれない。調べてみたところ、コードに含まれる same_network() 関数内で使われている&演算子の挙動の問題のようだ。Stretch Raspbianに含まれるperlは、文字列同士に対して&演算子を使った場合、1文字ずつを整数としてビット演算を行ってしまうらしく、例えば print "192" & "255"
の場合、整数同士の演算として192が出力されてほしいところだが、実際には以下のコードと等価となり、文字列"010"が出力されてしまう。
my $a = 1 & 2;
my $b = 9 & 5;
my $c = 2 $ 5;
print $a . $b . $c;
perlを触るのはほぼ初めてなので(大昔、ホームページにCGIだかSSIだかを入れる時にperlスクリプトをサーバに入れたことはあるけど単にソースをサーバに保存しただけだし)これで正しいやりかたかはわからないけど、
my $a = shift(@a) & $_;
my $b = shift(@b) & $_;
となっている箇所を、
my $a = (shift(@a) + 0) & ($_ + 0);
my $b = (shift(@b) + 0) & ($_ + 0);
としたら、パケットの転送をやってくれるようになった。このスクリプトは以下の挙動をするようだ。
マルチキャストのパケットを受信すると、受信したのとは別のネットワークインターフェースからマルチキャストパケットを新たに送信すると共に(送信元はルータ)、元々の送信元のIPアドレスとポートを記憶しておく。
サーバから返信のパケットがルータ宛に届くと、そのパケットをコピーして(送信元はルータ)記憶されたIPアドレス:ポートに送信する。
ルータ、サーバでtcpdumpを実行しつつ実行してPS3側からサーバの検索をやってみたところ、確かに返信のユニキャストパケットがPS3に送られていることを確認したが、PS3はサーバを見つけてくれない。正常ならサーバ側にPS3からhttpのリクエストがあるはずだが、PS3からの(httpなのでプロキシ経由の)パケットはサーバに届いていない(送られていない)。原因としては以下のものが考えられる。
ユニキャストパケットの送信元IPアドレス(ルータの有線LAN側のIPアドレス)と、パケットに含まれるメッセージに記載のURLのIPアドレスが不一致であるため、PS3側でユニキャストパケットをリジェクトしている。
そもそもPS3のDLNAクライアントは自ネットワークセグメント以外へのアクセスを行わないようになっている。
1.ならルータでパケットの送信元IPアドレスを書き換えればいけそうだけど、やり方がわからない。DLNAサーバが管理してるデータは10Gも無いので、ルータ側でDLNAサーバを構築するのが良さそう。
調べたところ、minidlnaというのが良さそうなのでこれを入れてみた。やり方はWebマーケット有限会社のサイトに書いてある通り。今後はCDを追加する度にrsyncで同期させればいいかなと。