C++11 OpenSSL DTLS服务器实现(C+;+;) 我尝试在C++中实现DTLS服务器包装器。 我打算做的是当我收到一条消息时,如果客户不知道,那么假设这是一次握手,并尝试完成它。 如果客户机是已知的,则假定它是常规会话消息

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

我在这里遇到的问题是,我的程序希望发送两次相同的消息以正确处理它(一次用于“对等方是否已知?”部分,一次用于SSL_accept/SSL_read部分)

我假设我没有正确设置BIOs,但我不知道正确的方法是什么

以下是我的文件目前的样子:

/*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;
}