UDP Hole Punching возвращает ICMP порт недоступен - PullRequest
0 голосов
/ 13 февраля 2020

Я пытался реализовать UDP Hole Punching в Kotlin / JVM, но он не работает так, как ожидалось. Отображения создаются в таблице NAT, и пакеты отправляются правильно, но мой NAT по-прежнему отклоняет их.

val peer1 = Peer(InetSocketAddress(5555)) // random port
    val global1 = peer1.requestSTUN()
    val peer2 = Peer(InetSocketAddress(6666)) // random port
    val global2 = peer2.requestSTUN()
    val bytes = "HELLO WORLD".toByteArray()
    peer1.socket.close() // close old socket used for creating new one
    peer2.socket.close() //

    peer1.local = InetSocketAddress(5555) // create new sockets
    peer1.socket = peer1.prepareSocket() // 
    peer2.local = InetSocketAddress(6666) //
    peer2.socket = peer2.prepareSocket() //

    println("CONNECT ${peer2.socket.localSocketAddress}$global2 to $global1")
    peer2.socket.send(DatagramPacket(ByteArray(0), 0, global1))
    println("PUNCH ${peer2.socket.localSocketAddress}$global2 to $global1")

    println("CONNECT ${peer1.socket.localSocketAddress}$global1 to $global2")
    peer1.socket.send(DatagramPacket(bytes, bytes.size, global2))
    println("PUNCH ${peer1.socket.localSocketAddress}$global1 to $global2")



    Thread { // ignored {} is just a function that cathes and outputs exception
        println(peer1.requestSTUN())
        repeat(500) {
            peer1.socket.send(DatagramPacket(bytes, bytes.size, global2))
            Thread.sleep(50)
        }
    }.start()
    Thread {
        println(peer2.requestSTUN())
        repeat(500) {
            peer2.socket.send(DatagramPacket(bytes, bytes.size, global1))
            Thread.sleep(50)
        }
    }.start()
    Thread {
        repeat(50) {
            ignored {
                val receive = DatagramPacket(bytes, bytes.size)
                peer1.socket.receive(receive)
                println(String(receive.data))
            }
        }
    }.start()
    Thread {
        repeat(50) {
            ignored {
                val receive = DatagramPacket(bytes, bytes.size)
                peer2.socket.receive(receive)
                println(String(receive.data))
            }
        }
    }.start()

Вывод:

CONNECT 0.0.0.0/0.0.0.0:5555/178.162.116.157:5555 to /178.162.116.157:6666
PUNCH 0.0.0.0/0.0.0.0:5555/178.162.116.157:5555 to /178.162.116.157:6666
CONNECT 0.0.0.0/0.0.0.0:6666/178.162.116.157:6666 to /178.162.116.157:5555
PUNCH 0.0.0.0/0.0.0.0:6666/178.162.116.157:6666 to /178.162.116.157:5555

И затем он генерирует исключение SocketTimeoutException. Мой NAT является не симметричным c, потому что запросы к разным серверам STUN из одного сокета возвращают одинаковые внешние IP-адреса. Я проверил журнал Wireshark и похоже, что пакеты отклонены и сообщение ICMP Port Unavailable отправлено обратно. Если я использую один и тот же сокет для запроса к серверу STUN и для запроса к месту назначения, ничего не изменится.

...