Zapis strumienia wyjściowego VpnService nie zapewnia odpowiedzi
Moja aplikacja implementuje usługę VpnService, aby przechwytywać ruch sieciowy i zapewniać dostosowane odpowiedzi. Celem jest obsługa ruchu do określonych adresów i odrzucanie innych żądań.
Obecnie z powodzeniem analizuję przychodzące żądania i konstruuję i wysyłam odpowiedzi. Problem polega jednak na tym, że odpowiedzi te nie pojawiają się jako rzeczywista odpowiedź na pierwotne żądanie; testowanie z połączeniem gniazdowym kończy się po prostu.
Aby dokonać tego rozróżnienia, obecnie analizuję surowe pakiety IP ze strumienia wejściowego VpnService w następujący sposób:
VpnService.Builder b = new VpnService.Builder();
b.addAddress("10.2.3.4", 28);
b.addRoute("0.0.0.0", 0);
b.setMtu(1500);
...
ParcelFileDescriptor vpnInterface = b.establish();
final FileInputStream in = new FileInputStream(
vpnInterface.getFileDescriptor());
final FileOutputStream out = new FileOutputStream(
vpnInterface.getFileDescriptor());
// Allocate the buffer for a single packet.
ByteBuffer packet = ByteBuffer.allocate(32767);
// We keep forwarding packets till something goes wrong.
try {
while (vpnInterface != null && vpnInterface.getFileDescriptor() != null
&& vpnInterface.getFileDescriptor().valid()) {
packet.clear();
SystemClock.sleep(10);
// Read the outgoing packet from the input stream.
final byte[] data = packet.array();
int length = in.read(data);
if (length > 0) {
packet.limit(length);
/*
1. Parse the TCP/UDP header
2. Create an own socket with the same src/dest port/ip
3. Use protect() on this socket so it not routed over tun0
4. Send the packet body (excluding the header)
5. Obtain the response
6. Add the TCP header to the response and forward it
*/
final IpDatagram ip = IpDatagram.create(packet);
...
}
}
IpDatagram to klasa, przez którącreate()
analizuje tablicę bajtów w reprezentację pakietu IP, zawierającą nagłówek IP, opcje i treść. Kontynuuję analizowanie tablicy bajtów ciała zgodnie z typem protokołu. W tym przypadku interesuje mnie tylko IPv4 z ładunkiem TCP - tutaj również tworzę reprezentację nagłówka TCP, opcji i treści.
Po uzyskaniu instancji IpDatagram mogę określić źródłowy i docelowy adres IP (z nagłówka IP) i port (z nagłówka TCP). Potwierdzam również flagi TCP żądania (takie jak SYN, ACK i PSH) i numer kolejny. W aplikacji:
Następnie konstruuję nowy IpDatagram jako odpowiedź, gdzie:
Źródłowy i docelowy adres IP są odwracane od przychodzącego żądania;Porty źródłowe i docelowe są odwracane od przychodzącego żądania;Numer potwierdzenia TCP jest ustawiony na numer kolejny przychodzącego żądania;Fałszywy ładunek HTTP / 1.1 jest dostarczany jako ciało TCP.Konwertuję wynikowy IpDatagram na tablicę bajtów i zapisuję go w strumieniu wyjściowym VpnServer:
TcpDatagram tcp = new TcpDatagram(tcpHeader, tcpOptions, tcpBody);
IpDatagram ip = new Ip4Datagram(ipHeader, ipOptions, tcp);
out.write(ip.toBytes());
Moja aplikacja wyświetla wychodzący datagram w takiej postaci, w jakiej powinien być, ale mimo to wszystkie połączenia nadal się wyczerkują.
Oto przykładowy przychodzący pakiet TCP / IP w systemie szesnastkowym:
4500003c7de04000400605f10a0203044faa5a3bb9240050858bc52b00000000a00239089a570000020405b40402080a00bfb8cb0000000001030306
A wynikowy pakiet TCP / IP wychodzący w systemie szesnastkowym:
450000bb30394000800613194faa5a3b0a0203040050b92400a00000858bc52b501820001fab0000485454502f312e3120323030204f4b0a446174653a205475652c203139204e6f7620323031332031323a32333a303320474d540a436f6e74656e742d547970653a20746578742f68746d6c0a436f6e74656e742d4c656e6774683a2031320a457870697265733a205475652c203139204e6f7620323031332031323a32333a303320474d540a0a48656c6c6f20776f726c6421
Jednak prosty test po prostu się kończy; Tworzę nowe gniazdo i podłączam je do powyższego adresu IP, ale powyższa odpowiedź nigdy nie nadchodzi.
Co może być nie tak? Czy jest jakiś sposób na rozwiązanie problemu, dlaczego moja odpowiedź nie dociera?