異なるネットワークセグメントにあるPS3からDLNAサーバにアクセスしようとしてうまく行かなかった話

Raspberry Pi3B+でルータを作った話の続き。

ラズパイの後ろ(有線LAN側)にプレステ3(と15年前の最初期のフルHDテレビ。D端子のみでHDMI無し)を設置して、手前(無線LAN側)にあるDLNAサーバにアクセスできないかとやってみて結局できなかったのでメモ。

UPnPの仕組み

nabeの雑記帳の「UPnP/SSDPマルチキャスト中継プログラム(DLNA用)」によれば以下の通り。

  1. クライアントは239.255.255.250:1900のUDPパケットを出力する。これはマルチキャストアドレスで同一ネットワークセグメントにある全てのホストに送られる。

  2. UDPパケットを受け取ったサーバは、送信元ポート1900のパケットをクライアントに送り返す。このパケットには、クライアントがサーバにアクセスするための情報を記したURLが含まれている。

  3. クライアントは上記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);

としたら、パケットの転送をやってくれるようになった。このスクリプトは以下の挙動をするようだ。

  1. マルチキャストのパケットを受信すると、受信したのとは別のネットワークインターフェースからマルチキャストパケットを新たに送信すると共に(送信元はルータ)、元々の送信元のIPアドレスとポートを記憶しておく。

  2. サーバから返信のパケットがルータ宛に届くと、そのパケットをコピーして(送信元はルータ)記憶されたIPアドレス:ポートに送信する。

ルータ、サーバでtcpdumpを実行しつつ実行してPS3側からサーバの検索をやってみたところ、確かに返信のユニキャストパケットがPS3に送られていることを確認したが、PS3はサーバを見つけてくれない。正常ならサーバ側にPS3からhttpのリクエストがあるはずだが、PS3からの(httpなのでプロキシ経由の)パケットはサーバに届いていない(送られていない)。原因としては以下のものが考えられる。

  1. ユニキャストパケットの送信元IPアドレス(ルータの有線LAN側のIPアドレス)と、パケットに含まれるメッセージに記載のURLのIPアドレスが不一致であるため、PS3側でユニキャストパケットをリジェクトしている。

  2. そもそもPS3のDLNAクライアントは自ネットワークセグメント以外へのアクセスを行わないようになっている。

1.ならルータでパケットの送信元IPアドレスを書き換えればいけそうだけど、やり方がわからない。DLNAサーバが管理してるデータは10Gも無いので、ルータ側でDLNAサーバを構築するのが良さそう。

調べたところ、minidlnaというのが良さそうなのでこれを入れてみた。やり方はWebマーケット有限会社のサイトに書いてある通り。今後はCDを追加する度にrsyncで同期させればいいかなと。

コメント(0)

コメントを投稿する際はここをクリック


Note

本サイトのハイパーリンクの一部は、オリジナルのサイトが閉鎖してしまったため"Internet archive Wayback Machine"へのリンクとなっています。そのようなリンクにはアイコン[archive]を付与しています。

本サイトはCookieを使用しています。本サイトにおけるCookieは以下の三種類のみであり、Cookieの内容に基づいてサイトの表示を変更する以外の用途には用いておりません。