Closed Ifilehk closed 1 year ago
Hi @Ifilehk! Thanks for opening this issue :)
Simply wrapping the connect()
in a try-catch block probably wouldn't work here, right? Would creating a custom exception that is only being thrown in the case of a failed handshake be an option here? Or do you maybe have a better suggestion?
Hmm, or is the problem rather that the client is trying to reuse a connection that has been cached before?
No wrapping connect does not catch it. I suppose the exception is not transmitted up stream in the code.
exception should come out in connection.listen((...) { ... }, on DtlsException { here }
No wrapping connect does not catch it. I suppose the exception is not transmitted up stream in the code.
Ah, I see! Hmm, maybe that is caused by the fact that the exception is thrown as part of a callback?
Possible ! thus not transmitted upstream. By the way if I remember well the Dtls Exception on send() works as expected.
Possible ! thus not transmitted upstream. By the way if I remember well the Dtls Exception on send() works as expected.
Here, the exception is actually being thrown directly:
I guess we figured out how to solve this problem then :) I will try to come up with a fix in the next few hours.
@Ifilehk Could you try out if #81 fixes the issue? :)
Unfortunately not yet fixed. Getting same Unhandled Exception.
E/flutter (12576): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: DtlsHandshakeException: DTLS Handshake has failed.
E/flutter (12576): #0 _DtlsClientConnection._performShutdown (package:dtls2/src/dtls_client.dart:492:7)
E/flutter (12576): #1 _DtlsClientConnection._connectToPeer (package:dtls2/src/dtls_client.dart:513:9)
E/flutter (12576): #2 _DtlsClientConnection._maintainState (package:dtls2/src/dtls_client.dart:597:7)
E/flutter (12576): #3 _DtlsClientConnection._incoming (package:dtls2/src/dtls_client.dart:558:5)
E/flutter (12576): #4 DtlsClient._startListening.<anonymous closure> (package:dtls2/src/dtls_client.dart:87:26)
Hmm, could you post a code snippet reproducing the issue? Or how the exception should be caught?
Here a test code against my dtls2 server.
Interesting to see also, not related to this bug but maybe to understand the flow, that is you use a correct identity and a wrong presharedkey, you get DTLS Connection ERROR: TIMEOUT EXCEPTION. I would expect in this case too a DTLS Exception or what do you think ?
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:dtls2/dtls2.dart';
void main(List<String> arguments) {
connect();
}
void connect() async {
try {
print("Connecting ...");
const bindAddress = "0.0.0.0";
DtlsClient dtlsClient = await DtlsClient.bind(bindAddress, 0);
DtlsConnection dtlsConnection = await dtlsClient.connect(
InternetAddress("XXX.XXX.XXX.XXX"),
XXXX,
DtlsClientContext(
verify : true,
withTrustedRoots : true,
ciphers : "PSK-AES128-CCM8",
pskCredentialsCallback: (identityHint) {
return PskCredentials(
//identity : ascii.encode('ID0'), // Valid identity
//preSharedKey : ascii.encode('mAKW-X437USLUGkMZEcass5nwpgcLQbN'), // Valid key
identity : ascii.encode('ID1'), // Invalid identity
preSharedKey : ascii.encode('OAKW-X437USLUGkMZEcass5nwpgcLQbN'), // Invalid key
);
},
),
timeout: const Duration(seconds: 10),
);
print('Connected');
dtlsConnection.listen((datagram) async {
print('Received datagram $datagram');
}, onDone: () {
print('DTLS Connection DONE');
}, onError: (e) {
print('DTLS Connection ERROR $e');
},);
} on DtlsException {
print('DTLS Connection ERROR: DTLS EXCEPTION');
} on SocketException {
print('DTLS Connection ERROR: SOCKET EXCEPTION');
} on TimeoutException {
print('DTLS Connection ERROR: TIMEOUT EXCEPTION');
} catch(e) {
print('Unhandled exception $e');
}
}
Hi @Ifilehk, thank you for the example! Unfortunately, I haven't been able to reproduce the issue using it :/ Could you maybe try using the altered example below (which uses the Californium test server) as a basis to replicate the issue (or integrate it with a server implementation)? This way I could try it out myself.
Good point regarding the TimeoutException
by the way, how about a DtlsTimeoutException
that extends the DtlsException
class and implements TimeoutException
? This way, we could have the best of both worlds, so to say. Edit: Done in #83.
// ignore_for_file: avoid_print
import "dart:async";
import "dart:convert";
import "dart:io";
import "package:dtls2/dtls2.dart";
void main(List<String> arguments) {
connect();
}
const host = "californium.eclipseprojects.io";
Future<InternetAddress> lookupAddress() async {
return (await InternetAddress.lookup(host, type: InternetAddressType.IPv6))
.first;
}
Future<void> connect() async {
final dtlsClient = await DtlsClient.bind(InternetAddress.anyIPv6, 0);
final address = await lookupAddress();
try {
print("Connecting ...");
final dtlsConnection = await dtlsClient.connect(
address,
5684,
DtlsClientContext(
withTrustedRoots: true,
ciphers: "PSK-AES128-CCM8",
pskCredentialsCallback: (identityHint) {
return PskCredentials(
identity: ascii.encode("Client_identity"),
preSharedKey: ascii.encode("secretPSK"),
);
},
),
timeout: const Duration(seconds: 10),
);
print("Connected");
dtlsConnection.listen(
(datagram) async {
print("Received datagram $datagram");
},
onDone: () {
print("DTLS Connection DONE");
},
onError: (e) {
print("DTLS Connection ERROR $e");
},
);
} on DtlsException {
print("DTLS Connection ERROR: DTLS EXCEPTION");
} on SocketException {
print("DTLS Connection ERROR: SOCKET EXCEPTION");
} on TimeoutException {
print("DTLS Connection ERROR: TIMEOUT EXCEPTION");
} catch (e) {
print("Unhandled exception $e");
}
dtlsClient.close();
}
OK will try it.
Regarding DtlsTimeoutException
. I don't understand it in this context. Of course the DtlsConnection ends with not beeing established, but the real cause is that the identity / preshared key pair is invalid. For the upper layer it makes sense to know the reason. And actually what is a DtlsTimeoutException
? I think it lacks a definition. In a connection Timeout means peer did not respond after a certain time. Here we have a response and an error that could give information to the client. What do you think ?
Cannot reproduce on your server. Could you try on mine ? 93.90.201.53 8888
Valid client: WERT PSK: P4OPmcvtHyZIhBjDSmPgGjM8V1Ykkp2D
Cannot reproduce on your server. Could you try on mine ? 93.90.201.53 8888
Valid client: WERT PSK: P4OPmcvtHyZIhBjDSmPgGjM8V1Ykkp2D
Thank you! That helped me a lot actually :) I think I now found the root cause of the problem and opened #85 as a potential fix. The bug was that an exception was thrown in the first place instead of using the Completer – this made it uncatchable from the outside.
Regarding
DtlsTimeoutException
. I don't understand it in this context. Of course the DtlsConnection ends with not beeing established, but the real cause is that the identity / preshared key pair is invalid. For the upper layer it makes sense to know the reason. And actually what is aDtlsTimeoutException
? I think it lacks a definition. In a connection Timeout means peer did not respond after a certain time. Here we have a response and an error that could give information to the client. What do you think ?
That's true, I think the TimeoutException should only be thrown in the case of an actual timeout, though. With the potential fix in #85, I think this should now rather be the case. For other scenarios, I think it should be possible to determine the reason why the Handshake has failed and create more fine-grained exceptions from that. I will have a look into it.
DTLS EXCEPTION
at the right place.
Thank you !!!
85 does the trick !!! Now client says:
DTLS EXCEPTION
at the right place.Thank you !!!
Awesome! Thank you for your error report! :) Then I will merge #85.
Hello, here an other point where I am struggling. Unable to catch DTLS Handshake has failed in this situation.
Client have a working dtls connection with the server. Server wants to ban the client. Client's presharedkey is then removed from the server. Client's tries to connect.
Result:
E/flutter (17787): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: DtlsException: DTLS Handshake has failed. E/flutter (17787): #0 _DtlsClientConnection._performShutdown (package:dtls2/src/dtls_client.dart:496:7) E/flutter (17787): #1 _DtlsClientConnection._connectToPeer.<anonymous closure> (package:dtls2/src/dtls_client.dart:518:15) E/flutter (17787): #2 _DtlsClientConnection._handleError (package:dtls2/src/dtls_client.dart:482:21) E/flutter (17787): #3 _DtlsClientConnection._connectToPeer (package:dtls2/src/dtls_client.dart:516:7) E/flutter (17787): #4 _DtlsClientConnection._maintainState (package:dtls2/src/dtls_client.dart:602:7) E/flutter (17787): #5 _DtlsClientConnection._incoming (package:dtls2/src/dtls_client.dart:563:5) E/flutter (17787): #6 DtlsClient._startListening.<anonymous closure> (package:dtls2/src/dtls_client.dart:87:26)
Would like to be able to catch this exeption to redirect the client to the signing page.
Thank you for your support.