Android VPNService — DatagramChannel не может записывать пакеты после вызова VPNService.installAndroid

Форум для тех, кто программирует под Android
Anonymous
Android VPNService — DatagramChannel не может записывать пакеты после вызова VPNService.install

Сообщение Anonymous »

Я работаю над проектом VPN для домашних животных для Android. Теперь мне нужно разработать приложение, которое бы отправляло все пакеты с устройства на удаленный сервер и получало от него ответ (без авторизации и шифрования данных). Серверная часть готова и работает нормально, но на клиентской стороне есть проблемы. После того, как я вызываю VPNService.install, мне возвращается ParcelFileDescriptor (т.е. на устройстве создается тун) и UDP-соединение с сервером пропадает. Я не могу отправлять пакеты на сервер, хотя до VPNService.install я могу без проблем общаться с сервером. Вот мой код VPNService:

Код: Выделить всё

class DPNService : VpnService() {

private val currentConnection = AtomicReference()

private val handshakeServiceListener = object : HandshakeService.Listener {
override fun onError(exception: Exception) {
Log.e(TAG, "Handshake error", exception)
}

override fun onSuccess(params: ServerParams, tunnel: DatagramChannel) {
protect(tunnel.socket())
updateNotification("VPN is connecting...")
val vpnInterface = configureVpnService(params)
vpnInterface?.let {
connect(tunnel, it)
}
}
}

override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
if (intent.action == ACTION_CONNECT) {
val tunnel = DatagramChannel.open()
if (protect(tunnel.socket())) {
val handshakeService = HandshakeService(tunnel, handshakeServiceListener)
handshakeService.sendHandshake()
}
return START_STICKY
}
if (intent.action == ACTION_DISCONNECT){
disconnect()
return START_NOT_STICKY
}

return super.onStartCommand(intent, flags, startId)
}

private fun connect(tunnel: DatagramChannel, vpnInterface: ParcelFileDescriptor?) {

val connection = DPNConnection(tunnel, vpnInterface)
val thread = Thread(connection, "DPN Connection")
setCurrentConnection(thread)
thread.start()
updateNotification("VPN is connected")
}

private fun configureVpnService(serverParams: ServerParams): ParcelFileDescriptor? {
val builder = this.Builder()
builder.addAddress(serverParams.address, serverParams.addressPrefixLength)
builder.addDnsServer(serverParams.dns)
builder.addRoute(serverParams.route, serverParams.routePrefixLength)
builder.setMtu(serverParams.mtu)

builder.addDisallowedApplication("com.google.chrome")
builder.addDisallowedApplication("com.werebug.androidnetcat")

builder.setSession(serverParams.address)
return builder.establish()
}

private fun disconnect() {
setCurrentConnection(null)
stopSelf()
}

override fun onDestroy() {
disconnect()
}

private fun setCurrentConnection(thread: Thread?) {
// set new thread and interrupt old
currentConnection.getAndSet(thread)?.interrupt()
}

private fun updateNotification(message: String) {
val notificationManager = getSystemService(NOTIFICATION_SERVICE) as NotificationManager

val notificationChannel = NotificationChannel(
NOTIFICATION_CHANNEL_ID,
NOTIFICATION_CHANNEL_ID,
NotificationManager.IMPORTANCE_HIGH,
)
val notification = Notification.Builder(this, NOTIFICATION_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_vpn_key)
.setContentText(message)
.build()

notificationManager.createNotificationChannel(notificationChannel)
notificationManager.notify(1, notification)
}

companion object {
const val TAG = "DPNService"
const val ACTION_CONNECT = "DPNService.CONNECT"
const val ACTION_DISCONNECT = "DPNService.DISCONNECT"
const val NOTIFICATION_CHANNEL_ID = "DPN"
}
}

class DPNConnection(
private val tunnel: DatagramChannel,
private val vpnInterface: ParcelFileDescriptor?,
) : Runnable {

override fun run() {
var iteration = 0
while (iteration <  100) {
iteration++
try {
tunnel.sendMessage("Hello DPN Server Side".toByteArray())
} catch (e: Exception) {
Log.e(TAG, "DPNConnection", e)
}
}

tunnel.close()
}

private fun DatagramChannel.sendMessage(byteArray: ByteArray) {
val buffer = ByteBuffer.allocate(1024)
buffer.put(byteArray)
buffer.flip()
write(buffer)
}

companion object {
private const val TAG = "DPNConnection"
}
}
И вот исключение, которое я получаю при попытке отправить посылку:

Код: Выделить всё

DPNConnection
java.net.PortUnreachableException
at sun.nio.ch.DatagramDispatcher.write0(Native Method)
at sun.nio.ch.DatagramDispatcher.write(DatagramDispatcher.java:60)
at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)
at sun.nio.ch.IOUtil.write(IOUtil.java:65)
at sun.nio.ch.DatagramChannelImpl.write(DatagramChannelImpl.java:649)
at com.example.dpn.data.DPNConnection.sendMessage(DPNConnection.kt:35)
at com.example.dpn.data.DPNConnection.run(DPNConnection.kt:20)
at java.lang.Thread.run(Thread.java:1012)
Я ожидал, что увижу сообщение «Hello DPN Server Side» в журналах сервера. Но это сообщение не доходит до сервера и возможно не покидает устройство. Я смотрю в WireShark и не вижу никаких пакетов после вызова VpnService.install. Более того, если я отправляю пакет на этот порт с другого устройства, то серверная часть его читает

Подробнее здесь: https://stackoverflow.com/questions/785 ... g-vpnservi

Вернуться в «Android»