C++11 OpenSSL DTLS服务器实现(C+;+;) 我尝试在C++中实现DTLS服务器包装器。 我打算做的是当我收到一条消息时,如果客户不知道,那么假设这是一次握手,并尝试完成它。 如果客户机是已知的,则假定它是常规会话消息
我在这里遇到的问题是,我的程序希望发送两次相同的消息以正确处理它(一次用于“对等方是否已知?”部分,一次用于SSL_accept/SSL_read部分) 我假设我没有正确设置BIOs,但我不知道正确的方法是什么 以下是我的文件目前的样子:C++11 OpenSSL DTLS服务器实现(C+;+;) 我尝试在C++中实现DTLS服务器包装器。 我打算做的是当我收到一条消息时,如果客户不知道,那么假设这是一次握手,并尝试完成它。 如果客户机是已知的,则假定它是常规会话消息,c++11,server,openssl,dtls,C++11,Server,Openssl,Dtls,我在这里遇到的问题是,我的程序希望发送两次相同的消息以正确处理它(一次用于“对等方是否已知?”部分,一次用于SSL_accept/SSL_read部分) 我假设我没有正确设置BIOs,但我不知道正确的方法是什么 以下是我的文件目前的样子: /*server.hpp*/ #ifndef\u DTLS\u服务器_ #定义DTLS服务器_ #包括 如何设置BIOs以执行我希望它们执行的操作? 我必须创建自定义BIOs吗 提前感谢您的建议:) /* server.cpp */ #include &qu
/*server.hpp*/
#ifndef\u DTLS\u服务器_
#定义DTLS服务器_
#包括
如何设置BIOs以执行我希望它们执行的操作?
我必须创建自定义BIOs吗
提前感谢您的建议:)
/* server.cpp */
#include "server.hpp"
#include <unistd.h>
#include <iostream>
#include <thread>
char cookie_str[] = "cookie";
DTLSServer::DTLSServer(){}
DTLSServer::~DTLSServer()
{
i_dtlsMutex.lock();
for(auto &l_cli : i_clients)
{
removeClient(l_cli.first.first, l_cli.first.second);
}
SSL_CTX_free(i_ctx);
i_dtlsMutex.unlock();
}
std::string DTLSServer::autoConnect(const sockaddr_in &p_addr, const std::string p_string){
char l_strAddress[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &p_addr.sin_addr.s_addr, l_strAddress, INET_ADDRSTRLEN);
std::string l_addr(l_strAddress);
uint16_t l_port = ntohs(p_addr.sin_port);
std::lock_guard<std::mutex>l_guard(i_dtlsMutex);
auto l_cli = std::find_if(i_clients.begin(),i_clients.end(), // looking for {addr, port} in clients
[l_addr, l_port](const std::pair<std::pair<std::string, uint16_t>, client> &el) // {(addr,port),client}
{
return l_addr == el.first.first
&& l_port == el.first.second;
});
if(l_cli!=i_clients.end()) // found a client
{
std::cout << "received message from " << l_addr << ":" << l_port << std::endl;
std::string retString = l_cli->second.onMessage(p_string); // decyphers message
if(retString == "TO REMOVE")
removeClient(l_addr, l_port);
return retString;
}
else // new client
{
std::cout << "adding " << l_addr << ":" << l_port << std::endl;
client &l_client = createClient(l_addr, l_port); // adding new client
auto l_newcli = std::find_if(i_clients.begin(),i_clients.end(),
[l_addr, l_port](const std::pair<std::pair<std::string, uint16_t>, client> &el)
{
return l_addr == el.first.first
&& l_port == el.first.second;
});
if(l_newcli==i_clients.end())
{
std::cout << "couldn't find added client" << std::endl;
return "";
}
else
std::cout << "valid" << std::endl;
return l_newcli->second.onConnect(i_sock, p_string, i_ctx); // creating SSL session for new client
}
}
DTLSServer::client &DTLSServer::createClient(const std::string &p_addr, const uint16_t &p_port)
{
std::pair<std::string, uint16_t> l_pair = {p_addr,p_port};
i_clients.insert(std::pair<std::pair<std::string, uint16_t>, client>(l_pair,client()));
return i_clients.at(l_pair);
}
void DTLSServer::removeClient(const std::string &p_addr, const uint16_t &p_port)
{
auto l_cli = std::find_if(i_clients.begin(),i_clients.end(), // looking for {addr, port} in clients
[&p_addr, &p_port](const std::pair<std::pair<std::string, uint16_t>, client> &el) // {(addr,port),client}
{
return p_addr == el.first.first
&& p_port == el.first.second;
});
if(l_cli!=i_clients.end()){
SSL_free(l_cli->second.ssl);
l_cli->second.ssl = nullptr;
i_clients.erase(l_cli);
}
else
{
std::cout << "could not delete" << std::endl;
}
}
void DTLSServer::init(const int &sock)
{
i_sock = sock;
SSL_load_error_strings();
SSL_library_init();
OpenSSL_add_all_ciphers();
memcpy(cookie_str, "cookie", 7);
i_ctx = SSL_CTX_new(DTLS_server_method());
/*if(SSL_CTX_set_cipher_list(i_ctx, "AES256-SHA256")!=1) //CLIENT PART
{
std::cout << "Could not set cipher" << std::endl;
}*/
SSL_CTX_set_min_proto_version(i_ctx, DTLS1_2_VERSION);
SSL_CTX_use_certificate_chain_file(i_ctx, "server-cert.pem");
SSL_CTX_use_PrivateKey_file(i_ctx, "server-key.pem", SSL_FILETYPE_PEM);
int l_ret = SSL_CTX_load_verify_locations(i_ctx, "root-ca.pem", NULL);
fprintf(stderr, "SSL_CTX_load_verify_locations -> %d\n", l_ret);
l_ret = SSL_CTX_set_default_verify_file(i_ctx);
fprintf(stderr, "SSL_CTX_set_default_verify_file -> %d\n", l_ret);
SSL_CTX_set_verify(i_ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL);
SSL_CTX_set_cookie_generate_cb(i_ctx, generate_cookie);
SSL_CTX_set_cookie_verify_cb(i_ctx, verify_cookie);
}
std::string DTLSServer::client::onConnect(const uint16_t & p_sock, const std::string& p_msg, SSL_CTX *p_ctx)
{
std::cout << "about to connect" << std::endl;
ssl = SSL_new(p_ctx);
if(nullptr==ssl)
std::cout << "couldn't create ssl session" << std::endl;
bio = BIO_new_dgram(p_sock, BIO_NOCLOSE);
if(nullptr==bio)
std::cout << "couldn't create ssl bio" << std::endl;
SSL_set_bio(ssl, bio, bio);
//write(p_sock, p_msg.c_str(), p_msg.size());
//BIO_write(bio, p_msg.c_str(), p_msg.size());
int needed = BIO_get_read_request(bio);
std::cout << "about to accept"<< std::endl;
int ret = SSL_accept(ssl);
//int ret = 0;
std::cout << "accepted"<< std::endl;
if (ret < 0)
{
std::cout << "failed to complete Handshake as " << strerror(errno) << std::endl;
}
return "";
}
std::string DTLSServer::client::onMessage(const std::string& p_msg)
{
int err = BIO_write(bio, &p_msg[0], p_msg.size());
int needed = BIO_get_read_request(bio);
char l_msg[1500] = {0};
/*if(needed > 0)
std::cout << "critical error" << std::endl;*/
int ret = SSL_read(ssl, &l_msg[0], 1500);
if(ret < 0)
{
std::cout << "unvalid message" << std::endl;
return "TO REMOVE";
}
else if(0 == ret)
{
std::cout << "client to remove" << std::endl;
return "TO REMOVE";
}
else
{
std::cout << "valid message" << std::endl;
std::string l_m{l_msg};
return "MESSAGE IS : " + l_m;
}
return "";
}
int DTLSServer::generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)
{
memmove(cookie, cookie_str, sizeof(cookie_str)-1);
*cookie_len = sizeof(cookie_str)-1;
return 1;
}
int DTLSServer::verify_cookie(SSL *ssl, const unsigned char *cookie, unsigned int cookie_len)
{
return sizeof(cookie_str)-1==cookie_len && memcmp(cookie, cookie_str, sizeof(cookie_str)-1)==0;
}
/* main.cpp */
#include "server.hpp"
#include <iostream>
int main()
{
DTLSServer l_dtls;
int l_socket;
if ((l_socket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
std::cout << "Could not create socket. " << strerror(errno) << std::endl;
return 1;
}
struct sockaddr_in l_sendingAddress;
l_sendingAddress.sin_family = AF_INET;
inet_pton(AF_INET,
"127.0.0.19",
&l_sendingAddress.sin_addr.s_addr);
l_sendingAddress.sin_port = htons(8888);
//Binding socket
if(bind(l_socket,reinterpret_cast<sockaddr *>(&l_sendingAddress),sizeof(l_sendingAddress)) < 0)
{
std::cout << "Could not bind. " << strerror(errno) << std::endl;
return 1;
}
l_dtls.init(l_socket);
char l_buffer[2000] = {0};
sockaddr_in l_client;
socklen_t l_clientLen = sizeof(l_client);
while(1)
{
ssize_t l_bytesReceived = recvfrom(l_socket, &l_buffer, 2000, MSG_DONTWAIT, reinterpret_cast<sockaddr *>(&l_client), &l_clientLen);
if (l_bytesReceived == -1)
{
continue;
}
std::string l_string{l_buffer, static_cast<size_t>(l_bytesReceived)};
std::cout << l_dtls.autoConnect(l_client, l_string) << std::endl;
memset(l_buffer, 0, 2000);
}
return 0;
}