我写了一个小的 DTLS 服务器示例。在以下链接中有我的代码:
/****
DTLSPolicy.hpp
****/
#pragma once
#include<botan/tls_policy.h>
#include<array>
#include<any>
//ENUM Class for Future Versions
//DTLS_ANY is for a possible future feature if you can exclude some Versions. DTLS_ANY will show that no Version is excluded.
//e.g. if there were 1.0 , 1.2 , 1.5 ,2.0 you could set up DTLS_1_0 and exclude DTLS_1_5 as accepted. If DTLS_ANY is set it is not.
enum class DTLSVersion : unsigned int {
DTLS_ANY = 0,
DTLS_1_0 = 1,
DTLS_1_2 = 2
};
constexpr std::array<const char*,19> ACCEPT_ALL_CIPHERS{"AES-256/OCB(12)","AES-128/OCB(12)","ChaCha20Poly1305","AES-256/GCM","AES-128/GCM","AES-256/CCM","AES-128/CCM","AES-256/CCM(8)","AES-128/CCM(8)","Camellia-256/GCM","Camellia-128/GCM","ARIA-256/GCM", "ARIA-128/GCM", "AES-256", "AES-128","Camellia-256", "Camellia-128", "SEED","3DES" };
constexpr std::array<const char*, 4> ACCEPT_ALL_SIGNATURE_HASHES{ "SHA-512","SHA-384","SHA-256","SHA-1", };
constexpr std::array<const char*, 4> ACCEPT_ALL_MACS{ "AEAD","SHA-256","SHA-384","SHA-1" };
constexpr std::array<const char*, 8> ACCEPT_ALL_KEY_EXCHANGE_METHODS{ "SRP_SHA", "ECDHE_PSK", "DHE_PSK", "PSK", "CECPQ1", "ECDH", "DH", "RSA" };
constexpr std::array<const char*, 5> ACCEPT_ALL_SIGNATURE_METHODS{ "ECDSA","RSA","DSA","IMPLICIT","ANONYMOUS" };
class DTLSPolicy : public Botan::TLS::Policy
{
public:
enum class DTLSPolicyOptions : unsigned int {
//1-9 ALLOWED FEATURES
DTLS_OPTION_SET_ALLOWED_CIPHERS = 1,
DTLS_OPTION_SET_ALLOWED_SIGNATURE_HASHES = 2,
DTLS_OPTION_SET_ALLOWED_MACS = 3,
DTLS_OPTION_SET_ALLOW_KEY_EXCHANGE_METHODS = 4,
DTLS_OPTION_SET_ALLOW_SIGNATURE_METHODS = 5,
//10+ OTHER FEATURES
DTLS_OPTION_EXCLUDE_DTLS_VERSION = 10,
};
DTLSPolicy(DTLSVersion minimum);
~DTLSPolicy();
void setOption(DTLSPolicy::DTLSPolicyOptions option, std::any data);
//OVERRIDE FUNCTIONS
bool allow_dtls10() const override {
return this->dtls10_enabled;
}
bool allow_dtls12() const override {
return this->dtls12_enabled;
}
bool allow_tls10() {
return false;
}
bool allow_tls11() {
return false;
}
std::vector<std::string> allowed_ciphers() const override {
return this->allowedCiphersVec;
}
std::vector<std::string> allowed_signature_hashes() const override {
return this->allowedSignatureHashesVec;
}
std::vector<std::string> allowed_macs() const override {
return this->allowedMacsVec;
}
std::vector<std::string> allowed_key_exchange_methods() const override {
return this->allowedKeyExchangeMethodsVec;
}
std::vector<std::string> allowed_signature_methods() const override {
return this->allowedSignatureMethodsVec;
}
private:
bool dtls10_enabled = false;
bool dtls12_enabled = false;
std::vector<std::string> allowedCiphersVec;
std::vector<std::string> allowedSignatureHashesVec;
std::vector<std::string> allowedMacsVec;
std::vector<std::string> allowedKeyExchangeMethodsVec;
std::vector<std::string> allowedSignatureMethodsVec;
bool noexclusion = false;
void excludeVersion(DTLSVersion version);
};
// END
/***
DTLSPolicy.cpp
***/
#include "DTLSPolicy.hpp"
#include<iostream>
DTLSPolicy::DTLSPolicy(DTLSVersion minimum)
{
switch (minimum) {
case DTLSVersion::DTLS_ANY:
this->noexclusion = true;
case DTLSVersion::DTLS_1_0:
this->dtls10_enabled = true;
case DTLSVersion::DTLS_1_2:
this->dtls12_enabled = true;
break;
default:
std::cerr << "This should not be reached!\n";
break;
}
}
DTLSPolicy::~DTLSPolicy()
{
}
//std::any for future options!
void DTLSPolicy::setOption(DTLSPolicy::DTLSPolicyOptions option, std::any data)
{
switch (option) {
case DTLSPolicy::DTLSPolicyOptions::DTLS_OPTION_SET_ALLOWED_CIPHERS:
{
this->allowedCiphersVec = std::any_cast<std::vector<std::string>>(data);
}
return;
case DTLSPolicy::DTLSPolicyOptions::DTLS_OPTION_SET_ALLOWED_SIGNATURE_HASHES:
{
this->allowedSignatureHashesVec = std::any_cast<std::vector<std::string>>(data);
}
return;
case DTLSPolicy::DTLSPolicyOptions::DTLS_OPTION_SET_ALLOWED_MACS:
{
this->allowedMacsVec = std::any_cast<std::vector<std::string>>(data);
}
return;
case DTLSPolicy::DTLSPolicyOptions::DTLS_OPTION_SET_ALLOW_KEY_EXCHANGE_METHODS:
{
this->allowedKeyExchangeMethodsVec = std::any_cast<std::vector<std::string>>(data);
}
return;
case DTLSPolicy::DTLSPolicyOptions::DTLS_OPTION_SET_ALLOW_SIGNATURE_METHODS:
{
this->allowedSignatureMethodsVec = std::any_cast<std::vector<std::string>>(data);
}
return;
case DTLSPolicy::DTLSPolicyOptions::DTLS_OPTION_EXCLUDE_DTLS_VERSION:
{
this->excludeVersion(std::any_cast<DTLSVersion>(data));
}
return;
default:
std::cerr << "This should not be reached!\n";
return;
}
}
void DTLSPolicy::excludeVersion(DTLSVersion version)
{
if (this->noexclusion) return;
switch (version) {
case DTLSVersion::DTLS_1_0:
this->dtls10_enabled = false;
return;
case DTLSVersion::DTLS_1_2:
this->dtls12_enabled = false;
return;
case DTLSVersion::DTLS_ANY:
default:
std::cerr << "OPERATION NOT POSSIBLE\n";
return;
}
}
//END
/***
DTLS.hpp
***/
#pragma once
#define _WINSOCKAPI_ // stop windows.h including winsock.h
#pragma comment(lib,"botan.lib")
#include<iostream>
//BOTAN
#include<botan/tls_server.h>
#include <botan/tls_client.h>
#include <botan/tls_callbacks.h>
#include <botan/tls_session_manager.h>
#include <botan/tls_policy.h>
#include <botan/auto_rng.h>
#include <botan/certstor.h>
#include <botan/pk_keys.h>
#include<botan/hex.h>
#include<botan/certstor.h>
#include<botan/pkcs8.h>
#include<botan/data_src.h>
#pragma comment(lib,"ws2_32.lib")
#include<WinSock2.h>
#include<fstream>
#include"DTLSPolicy.hpp"
class Server_Credentials : public Botan::Credentials_Manager
{
private:
std::unique_ptr<Botan::Private_Key> m_key;
// Botan::DataSource_Stream stream;
std::ifstream file;
public:
Server_Credentials()
{
}
std::vector<Botan::Certificate_Store*> trusted_certificate_authorities(
const std::string& type,
const std::string& context) override
{
// if client authentication is required, this function
// shall return a list of certificates of CAs we trust
// for tls client certificates, otherwise return an empty list
return std::vector<Botan::Certificate_Store*>();
}
std::vector<Botan::X509_Certificate> cert_chain(
const std::vector<std::string>& cert_key_types,
const std::string& type,
const std::string& context) override
{
// return the certificate chain being sent to the tls client
// e.g., the certificate file "botan.randombit.net.crt"
return { Botan::X509_Certificate("botan.randombit.net.crt") };
}
Botan::Private_Key* private_key_for(const Botan::X509_Certificate& cert,
const std::string& type,
const std::string& context) override
{
// return the private key associated with the leaf certificate,
// in this case the one associated with "botan.randombit.net.crt"
return &*m_key;
}
};
class DTLS : public Botan::TLS::Callbacks
{
public:
DTLS(const std::string& ip, unsigned int port, Botan::TLS::Policy& policy);
~DTLS();
void startReceiving();
void tls_emit_data(const uint8_t buf[], size_t length) override {
sendto(this->servSocket, (char*)buf, length, 0, (SOCKADDR*)& this->clientAddr, sizeof(SOCKADDR_IN));
startReceiving();
}
void tls_alert(Botan::TLS::Alert alert) override {
std::cout << alert.type_string();
}
void tls_record_received(uint64_t seq_no, const uint8_t input[], size_t length) override {
std::string t = "";
for (size_t i = 0; i < length; ++i) {
t += static_cast<char>(input[i]);
if (t[t.length() - 1] == '\t') {
std::cout << t << '\n';
t.clear();
}
}
}
bool tls_session_established(const Botan::TLS::Session& session) override {
std::cout << "DETAILS:\n"
<< "SESSION ID=" << Botan::hex_encode(session.session_id()) << '\n'
<< "Session Ticket=" << Botan::hex_encode(session.session_ticket()) << '\n';
return true;
}
private:
Botan::AutoSeeded_RNG rng;
Botan::TLS::Session_Manager_In_Memory session_mgr;
Botan::Credentials_Manager creds;
Botan::TLS::Policy policy;
Botan::TLS::Server server;
SOCKET servSocket;
SOCKADDR_IN servAddr;
SOCKADDR_IN clientAddr;
};
//END
/***
DTLS.cpp
***/
#include "DTLS.hpp"
#include<botan/exceptn.h>
#include<ws2tcpip.h>
DTLS::DTLS(const std::string& ip, unsigned int port, Botan::TLS::Policy& policy) : policy(policy),session_mgr(this->rng), server(*this,this->session_mgr,this->creds,this->policy,this->rng,true)
{
WSAData d;
WSAStartup(MAKEWORD(2, 0), &d);
this->servSocket = socket(AF_INET, SOCK_DGRAM, 0);
this->servAddr.sin_family = AF_INET;
this->servAddr.sin_port = htons(port);
char addr[666];
if (ip != "ANY")
this->servAddr.sin_addr.S_un.S_addr = ADDR_ANY;
else
this->servAddr.sin_addr.S_un.S_addr = ADDR_ANY;
auto rc = bind(this->servSocket, (SOCKADDR*)& this->servAddr, sizeof(SOCKADDR_IN));
#ifndef _NO_DEBUG
if (rc == SOCKET_ERROR)
std::cout << "COULD NOT BIND!\n";
else
std::cout << "SUCCESSFULLY SOCKET BIND\n";
#endif
}
DTLS::~DTLS()
{
WSACleanup();
}
void DTLS::startReceiving()
{
try {
uint8_t buffer[1024];
memset(buffer, 0, sizeof(buffer));
int size = sizeof(SOCKADDR_IN);
auto rc = recvfrom(this->servSocket, (char*)buffer, sizeof(buffer), 0, (SOCKADDR*)& this->clientAddr, &size);
buffer[rc] = '\0';
std::cout << buffer << '\n';
this->server.received_data(buffer, rc);
}
catch (Botan::Exception & ex) {
std::cout << ex.what();
system("pause");
}
}
//END
/***
Quelle.cpp TESTMAIN
***/
#include"DTLS.hpp"
int main() {
DTLSPolicy policy(DTLSVersion::DTLS_ANY);
policy.setOption(DTLSPolicy::DTLSPolicyOptions::DTLS_OPTION_SET_ALLOWED_CIPHERS, std::vector<std::string>(ACCEPT_ALL_CIPHERS.begin(), ACCEPT_ALL_CIPHERS.end()));
policy.setOption(DTLSPolicy::DTLSPolicyOptions::DTLS_OPTION_SET_ALLOWED_MACS, std::vector<std::string>(ACCEPT_ALL_MACS.begin(), ACCEPT_ALL_MACS.end()));
policy.setOption(DTLSPolicy::DTLSPolicyOptions::DTLS_OPTION_SET_ALLOWED_SIGNATURE_HASHES, std::vector<std::string>(ACCEPT_ALL_SIGNATURE_HASHES.begin(), ACCEPT_ALL_SIGNATURE_HASHES.end()));
policy.setOption(DTLSPolicy::DTLSPolicyOptions::DTLS_OPTION_SET_ALLOW_KEY_EXCHANGE_METHODS, std::vector<std::string>(ACCEPT_ALL_KEY_EXCHANGE_METHODS.begin(), ACCEPT_ALL_KEY_EXCHANGE_METHODS.end()));
policy.setOption(DTLSPolicy::DTLSPolicyOptions::DTLS_OPTION_SET_ALLOW_SIGNATURE_METHODS, std::vector<std::string>(ACCEPT_ALL_SIGNATURE_METHODS.begin(), ACCEPT_ALL_SIGNATURE_METHODS.end()));
Botan::TLS::Default_Policy p;
DTLS test("192.168.1.119", 999,p);
while (true) {
test.startReceiving();
Sleep(500);
}
system("pause");
}
我使用 Qt DTLS 示例客户端和 botan-cli.exe 进行了尝试,可以使用可在 botan github 站点上下载的文件进行编译。
即使我将它编码为与 Linux 一起使用,它也会抛出相同的错误。有人可以给我一个提示来解决我的问题吗?
我也通过 Wireshark 嗅探了通信,结果如下:
105 CLIENT
107 SERVER
CLIENT HALLO FROM 105 to 107
// START
Frame 161: 567 bytes on wire (4536 bits), 567 bytes captured (4536 bits) on interface 0
Ethernet II, Src: Micro-St_00:95:56 (30:9c:23:00:95:56), Dst: PcsCompu_0c:b9:9b (08:00:27:0c:b9:9b)
Internet Protocol Version 4, Src: 192.168.1.105, Dst: 192.168.1.107
User Datagram Protocol, Src Port: 58117, Dst Port: 999
Datagram Transport Layer Security
DTLSv1.2 Record Layer: Handshake Protocol: Client Hello
Content Type: Handshake (22)
Version: DTLS 1.2 (0xfefd)
Epoch: 0
Sequence Number: 0
Length: 512
Handshake Protocol: Client Hello
Handshake Type: Client Hello (1)
Length: 500
Message Sequence: 0
Fragment Offset: 0
Fragment Length: 500
Version: DTLS 1.2 (0xfefd)
Random: 75740133b67215d63de54c5c0369444eab560cf4117c34e3...
GMT Unix Time: Jun 11, 2032 05:19:15.000000000 CEST
Random Bytes: b67215d63de54c5c0369444eab560cf4117c34e3fb37095e...
Session ID Length: 0
Cookie Length: 0
Cipher Suites Length: 146
Cipher Suites (73 suites)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (0xc030)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02c)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 (0xc028)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 (0xc024)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA (0xc014)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA (0xc00a)
Cipher Suite: TLS_DH_DSS_WITH_AES_256_GCM_SHA384 (0x00a5)
Cipher Suite: TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 (0x00a3)
Cipher Suite: TLS_DH_RSA_WITH_AES_256_GCM_SHA384 (0x00a1)
Cipher Suite: TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 (0x009f)
Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 (0x006b)
Cipher Suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 (0x006a)
Cipher Suite: TLS_DH_RSA_WITH_AES_256_CBC_SHA256 (0x0069)
Cipher Suite: TLS_DH_DSS_WITH_AES_256_CBC_SHA256 (0x0068)
Cipher Suite: TLS_DHE_RSA_WITH_AES_256_CBC_SHA (0x0039)
Cipher Suite: TLS_DHE_DSS_WITH_AES_256_CBC_SHA (0x0038)
Cipher Suite: TLS_DH_RSA_WITH_AES_256_CBC_SHA (0x0037)
Cipher Suite: TLS_DH_DSS_WITH_AES_256_CBC_SHA (0x0036)
Cipher Suite: TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA (0x0088)
Cipher Suite: TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA (0x0087)
Cipher Suite: TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA (0x0086)
Cipher Suite: TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA (0x0085)
Cipher Suite: TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 (0xc032)
Cipher Suite: TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 (0xc02e)
Cipher Suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 (0xc02a)
Cipher Suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 (0xc026)
Cipher Suite: TLS_ECDH_RSA_WITH_AES_256_CBC_SHA (0xc00f)
Cipher Suite: TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA (0xc005)
Cipher Suite: TLS_RSA_WITH_AES_256_GCM_SHA384 (0x009d)
Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA256 (0x003d)
Cipher Suite: TLS_RSA_WITH_AES_256_CBC_SHA (0x0035)
Cipher Suite: TLS_RSA_WITH_CAMELLIA_256_CBC_SHA (0x0084)
Cipher Suite: TLS_PSK_WITH_AES_256_CBC_SHA (0x008d)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (0xc02f)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02b)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 (0xc027)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 (0xc023)
Cipher Suite: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA (0xc013)
Cipher Suite: TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA (0xc009)
Cipher Suite: TLS_DH_DSS_WITH_AES_128_GCM_SHA256 (0x00a4)
Cipher Suite: TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 (0x00a2)
Cipher Suite: TLS_DH_RSA_WITH_AES_128_GCM_SHA256 (0x00a0)
Cipher Suite: TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 (0x009e)
Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 (0x0067)
Cipher Suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 (0x0040)
Cipher Suite: TLS_DH_RSA_WITH_AES_128_CBC_SHA256 (0x003f)
Cipher Suite: TLS_DH_DSS_WITH_AES_128_CBC_SHA256 (0x003e)
Cipher Suite: TLS_DHE_RSA_WITH_AES_128_CBC_SHA (0x0033)
Cipher Suite: TLS_DHE_DSS_WITH_AES_128_CBC_SHA (0x0032)
Cipher Suite: TLS_DH_RSA_WITH_AES_128_CBC_SHA (0x0031)
Cipher Suite: TLS_DH_DSS_WITH_AES_128_CBC_SHA (0x0030)
Cipher Suite: TLS_DHE_RSA_WITH_SEED_CBC_SHA (0x009a)
Cipher Suite: TLS_DHE_DSS_WITH_SEED_CBC_SHA (0x0099)
Cipher Suite: TLS_DH_RSA_WITH_SEED_CBC_SHA (0x0098)
Cipher Suite: TLS_DH_DSS_WITH_SEED_CBC_SHA (0x0097)
Cipher Suite: TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA (0x0045)
Cipher Suite: TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA (0x0044)
Cipher Suite: TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA (0x0043)
Cipher Suite: TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA (0x0042)
Cipher Suite: TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 (0xc031)
Cipher Suite: TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 (0xc02d)
Cipher Suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 (0xc029)
Cipher Suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 (0xc025)
Cipher Suite: TLS_ECDH_RSA_WITH_AES_128_CBC_SHA (0xc00e)
Cipher Suite: TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA (0xc004)
Cipher Suite: TLS_RSA_WITH_AES_128_GCM_SHA256 (0x009c)
Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA256 (0x003c)
Cipher Suite: TLS_RSA_WITH_AES_128_CBC_SHA (0x002f)
Cipher Suite: TLS_RSA_WITH_SEED_CBC_SHA (0x0096)
Cipher Suite: TLS_RSA_WITH_CAMELLIA_128_CBC_SHA (0x0041)
Cipher Suite: TLS_RSA_WITH_IDEA_CBC_SHA (0x0007)
Cipher Suite: TLS_PSK_WITH_AES_128_CBC_SHA (0x008c)
Cipher Suite: TLS_EMPTY_RENEGOTIATION_INFO_SCSV (0x00ff)
Compression Methods Length: 1
Compression Methods (1 method)
Extensions Length: 312
Extension: ec_point_formats (len=4)
Extension: supported_groups (len=28)
Extension: SessionTicket TLS (len=0)
Extension: signature_algorithms (len=32)
Extension: heartbeat (len=1)
Extension: padding (len=223)
//ANSWER from SERVER
Frame 162: 57 bytes on wire (456 bits), 57 bytes captured (456 bits) on interface 0
Interface id: 0 (enp0s8)
Encapsulation type: Ethernet (1)
Arrival Time: Apr 28, 2019 00:39:12.189017567 CEST
[Time shift for this packet: 0.000000000 seconds]
Epoch Time: 1556404752.189017567 seconds
[Time delta from previous captured frame: 0.001734430 seconds]
[Time delta from previous displayed frame: 0.001734430 seconds]
[Time since reference or first frame: 43.162216943 seconds]
Frame Number: 162
Frame Length: 57 bytes (456 bits)
Capture Length: 57 bytes (456 bits)
[Frame is marked: False]
[Frame is ignored: False]
[Protocols in frame: eth:ethertype:ip:udp:dtls]
[Coloring Rule Name: UDP]
[Coloring Rule String: udp]
Ethernet II, Src: PcsCompu_0c:b9:9b (08:00:27:0c:b9:9b), Dst: Micro-St_00:95:56 (30:9c:23:00:95:56)
Destination: Micro-St_00:95:56 (30:9c:23:00:95:56)
Source: PcsCompu_0c:b9:9b (08:00:27:0c:b9:9b)
Type: IPv4 (0x0800)
Internet Protocol Version 4, Src: 192.168.1.107, Dst: 192.168.1.105
0100 .... = Version: 4
.... 0101 = Header Length: 20 bytes (5)
Differentiated Services Field: 0x00 (DSCP: CS0, ECN: Not-ECT)
Total Length: 43
Identification: 0x9c14 (39956)
Flags: 0x4000, Don't fragment
Time to live: 64
Protocol: UDP (17)
Header checksum: 0x1a89 [validation disabled]
[Header checksum status: Unverified]
Source: 192.168.1.107
Destination: 192.168.1.105
User Datagram Protocol, Src Port: 999, Dst Port: 58117
Source Port: 999
Destination Port: 58117
Length: 23
Checksum: 0x844d [unverified]
[Checksum Status: Unverified]
[Stream index: 35]
Datagram Transport Layer Security
DTLSv1.2 Record Layer: Alert (Level: Fatal, Description: Handshake Failure)
Content Type: Alert (21)
Version: DTLS 1.2 (0xfefd)
Epoch: 0
Sequence Number: 0
Length: 2
Alert Message
Level: Fatal (2)
Description: Handshake Failure (40)
我试图在 Botan::TLS::Policy 中重载 bool Acceptable_ciphersuite,这样它总是会返回 true,但它没有帮助。我用谷歌搜索了这个错误,但没有找到任何合适的解决方案。