- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
对于这么大的代码块,我感到很抱歉,但我对发生的事情感到非常困惑,我不知道问题可能出在哪里......
我正在尝试让一个非常小的 dtls 服务器运行,但我无法让客户端和服务器完成握手。
这是我的代码:
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/rand.h>
#include <openssl/opensslv.h>
int generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)
{
cookie = "cookie";
cookie_len = 5;
return 1;
}
int verify_cookie(SSL *ssl, const unsigned char *cookie, unsigned int cookie_len)
{
return 1;
}
int dtls_verify_callback (int ok, X509_STORE_CTX *ctx) {
/* This function should ask the user
* if he trusts the received certificate.
* Here we always trust.
*/
return 1;
}
int main() {
char buff[FILENAME_MAX];
getcwd(buff, FILENAME_MAX);
union {
struct sockaddr_storage ss;
struct sockaddr_in s4;
struct sockaddr_in6 s6;
} client_addr;
struct sockaddr_in server_addr;
const int on = 1, off = 0;
memset(&server_addr, 0, sizeof(server_addr));
memset(&client_addr, 0, sizeof(client_addr));
int res;
SSL *ssl;
BIO *bio;
int sock;
struct timeval timeout;
SSL_CTX *ctx = SSL_CTX_new(DTLS_server_method());
SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
if(!SSL_CTX_use_certificate_file(ctx, "/home/matthew/CLionProjects/OpenSSL.Test/cmake-build-debug/certs/cert.crt", SSL_FILETYPE_PEM))
{
perror("cert");
exit(EXIT_FAILURE);
}
if(!SSL_CTX_use_PrivateKey_file(ctx, "/home/matthew/CLionProjects/OpenSSL.Test/cmake-build-debug/certs/key.key", SSL_FILETYPE_PEM))
{
perror("key");
exit(EXIT_FAILURE);
}
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, dtls_verify_callback);
SSL_CTX_set_read_ahead(ctx, 1);
SSL_CTX_set_cookie_generate_cb(ctx, generate_cookie);
SSL_CTX_set_cookie_verify_cb(ctx, &verify_cookie);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(1114);
if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{
perror("socket");
exit(EXIT_FAILURE);
}
if(setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*) &on, (socklen_t) sizeof(on)) < 0)
{
perror("set reuse address");
exit(EXIT_FAILURE);
}
if(setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (const char*) &on, (socklen_t) sizeof(on)) < 0)
{
perror("set reuse port");
exit(EXIT_FAILURE);
}
if(bind(sock, (const struct sockaddr *) &server_addr, sizeof(server_addr)) < 0)
{
perror("bind");
exit(EXIT_FAILURE);
}
memset(&client_addr, 0, sizeof(struct sockaddr_storage));
/* Create BIO */
bio = BIO_new_dgram(sock, BIO_NOCLOSE);
/* Set and activate timeouts */
timeout.tv_sec = 5;
timeout.tv_usec = 0;
BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
ssl = SSL_new(ctx);
SSL_set_bio(ssl, bio, bio);
SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE);
if(!SSL_set_fd(ssl, sock))
{
perror("set fd");
exit(EXIT_FAILURE);
}
res = 0;
while(res <= 0)
{
res = DTLSv1_listen(ssl, (BIO_ADDR *) &client_addr);
if(res < 0)
{
perror("dtls listen"); <--- "Destination address required"
exit(EXIT_FAILURE);
}
}
SSL_accept(ssl);
printf("Hello, World!\n");
return 0;
}
我在我能想到的每个角落和缝隙中添加了错误检查......
发生的情况是,它会很好地循环 DTLSv1_accept()
直到尝试连接。一旦客户端尝试连接(发送 Client Hello),DTLSv1_accept()
返回 -1。对 SSL_get_error
的调用给出了 5,这是一个 SSL_ERROR_SYSCALL
。
所以我执行perror
并获取需要目标地址
...
据我所知,DTLSv1_listen
的全部意义在于监听任何传入的客户端问候,并在握手完成后用客户端的地址填充 BIO_ADDR
完成...
我用它来测试服务器:
openssl s_client -dtls -connect 127.0.0.1:1114
我在这上面花了很多时间。我即将放弃 OpenSSL 并尝试 libressl...
非常感谢任何帮助。
附注代码已经完成,如果您想尝试一下,它应该可以编译并运行。
谢谢!
最佳答案
您的代码示例中有两个重大问题。
首先,您生成 cookie 的代码不正确。你应该创建cookie并将其存储在cookie
指向的位置,然后在*cookie_len
中填写cookie的长度。所以代码应该是这样的:
int generate_cookie(SSL *ssl, unsigned char *cookie, unsigned int *cookie_len)
{
memcpy(cookie, "cookie", 6);
*cookie_len = 6;
return 1;
}
但是,在设置要使用的 SSL 对象时,最重要的错误出现了。 OpenSSL 具有用于抽象底层传输层的 BIO 概念。为了通过 UDP 执行 DTLS,您需要使用“dgram”BIO。你正确地做到了这一点:
/* Create BIO */
bio = BIO_new_dgram(sock, BIO_NOCLOSE);
/* Set and activate timeouts */
timeout.tv_sec = 5;
timeout.tv_usec = 0;
BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_RECV_TIMEOUT, 0, &timeout);
ssl = SSL_new(ctx);
SSL_set_bio(ssl, bio, bio);
因此,此时已为 DTLSv1_listen()
调用正确设置 SSL 对象。但是,您可以这样做:
if(!SSL_set_fd(ssl, sock))
{
perror("set fd");
exit(EXIT_FAILURE);
}
SSL_set_fd
函数是 SSL_set_bio
函数的替代函数。它的作用是获取提供的fd
,将其包装在“套接字”BIO 中,然后使用结果调用SSL_set_bio()
。套接字 BIO 主要用于标准 TLS,不能用于 DTLS。所以上面代码的作用就是扔掉你之前设置的dgram BIO。
在我的测试中,如果我进行了上面建议的 generate_cookie
更改,并删除了 SSL_set_fd
行,那么一切都会按预期开始工作。
关于c - OpenSSL DTLS 连接从未建立,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57213219/
背景 我最近在 merge 期间遇到了一个意外未 merge 的文档文件的问题。 无论出于何种原因,我搞砸了 merge 并有效地删除了文件(和其他几个文件),因为我忘记了它们的存在。 现在我想查看我
我在我的网站上使用旧的 mysql 版本和 php 版本 4。 我的表结构: | orders_status_history_id | orders_id | orders_status_id |
我是一名优秀的程序员,十分优秀!