Android用のファイアウォール/フィルタリングアプリケーションを作成する際に、似たようなことをしようとしています. 私はこの真っ只中にいるので、適切な大きさの塩の粒で私が言うことを受け取ってください. :-)
あなた/私の状況の問題は、VpnService によって提供された仮想ネットワーク インターフェイスからパケットを取得しているが、それらのパケットを取得してソケットで書き込んでいることです。ソケットは、パケットではなく、クライアントとサーバー間のアプリケーション ペイロードの転送を処理することを目的としています。
ソケットは、渡されたデータを受け取り、そのデータを独自に作成したパケット内にラップします (Socket を使用する場合は TCP、DatagramSocket を使用する場合は UDP)。あなたの場合、ソケットを処理しているデータ自体がパケットであるため、最終的にパケット内のパケットになります (UDP パケット内の TCP パケットの可能性があります)。
ラップされたパケットがソケットのサーバーに到着すると、その側のネットワーク インターフェイスと ServerSocket はペイロードをラップ解除し、それが別のパケットであることを検出します。サーバー側のソケット (Web サーバーなど) から読み取っているものはすべて、アプリケーションのペイロード (HTTP ヘッダーなど) を予期しているため、おそらく機能しません。
実際の VPN トンネルがある場合、そのトンネルのサーバー側はおそらく、受信した UDP パケットから「ラップされたパケット」ペイロードを引き出し、そのパケットを、パケット自体を解釈できるネットワーク インターフェイスに直接渡します。 .
この実際の VPN トンネルがなければ、VpnService impl は本質的にそれ自体が仮想ネットワーク インターフェイスになり、TCP/UDP などを処理する必要があります。仮想ネットワーク インターフェイスとコードの間のプロトコル。基本的に、VPN インターフェースから読み取られたパケットは、送信ソケットに書き込む前に、アプリケーション データ ストリーム (パケットを照合して再構成) として処理する必要があります。次に、インターフェイスから消費したばかりのパケットを何らかの方法で確認する必要があります。次に、ソケット (ペイロード データ ストリーム) から着信データを取得し、VPN インターフェースの出力ストリームに送り返すことができるパケットに分割する必要があります。最後に、仮想 VPN インターフェイスが、送信したパケットに応答して送信する受信確認トラフィックを処理する必要があります。これは簡単なことではありません。
このすべてについて私が間違っていることを本当に願っています.Javaで書かれた単純な「仮想ネットワークインターフェイス」を誰かが持っているので、実際のVPNトンネルの代わりに使用できます. 私はそれを見つけることができませんでした。