2016-08-04 2 views
1

У меня есть демо-код dtls, он хорошо работает с ipv4. но после того, как я изменил его для ipv6, он не справляется на этапе рукопожатия. Серверный код, как это:Сбой установления связи DTLS на ipv6

SSL_load_error_strings(); 
SSL_library_init(); 
SSL_CTX *ctx = SSL_CTX_new(DTLSv1_server_method()); 
if(SSL_CTX_use_certificate_chain_file(ctx, "path/to/crt") !=1) 
    ERR_print_errors_fp(stderr); 

if(SSL_CTX_use_PrivateKey_file(ctx, "path/to/key", SSL_FILETYPE_PEM) != 1) 
    ERR_print_errors_fp(stderr); 

SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, verify_cert); 
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); 
SSL_CTX_set_cipher_list(ctx, "ALL:NULL:eNULL:aNULL"); 

int fd = socket(AF_INET6, SOCK_DGRAM, 0); 
struct sockaddr_in6 server_addr; 
memset(&server_addr, 0, sizeof(server_addr)); 
server_addr.sin6_family = AF_INET6; 
server_addr.sin6_port = htons(MYPORT); 
server_addr.sin6_addr = in6addr_any; 
int flag = 1; 
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) < 0) 
    perror("server reuse addr"); 

#ifdef SO_REUSEPORT 
if (setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag)) < 0) 
    perror("server reuse port"); 
#endif 
if(bind(fd, (struct sockaddr *)&server_addr, sizeof(server_addr))) 
    perror("bind server fd"); 

BIO *bio = BIO_new_dgram(fd, BIO_NOCLOSE); 
SSL *ssl = SSL_new(ctx); 
SSL_set_bio(ssl, bio, bio); 

/* Enable cookie exchange */ 
SSL_set_options(ssl, SSL_OP_COOKIE_EXCHANGE); 


fprintf(stderr, "Wait for incoming connections\n"); 
struct sockaddr_in6 client_addr; 
while(1){ 
    int ret = DTLSv1_listen(ssl, &client_addr); 
    if(ret < 0){ 
     ERR_print_errors_fp(stderr); 
    } 
    if(ret > 0) 
     break; 
} 
fprintf(stderr, "Handle client connection\n"); 
int client_fd = socket(client_addr.sin6_family, SOCK_DGRAM, 0); 
if (setsockopt(client_fd, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) < 0) 
    perror("reuse addr"); 

#ifdef SO_REUSEPORT 
if (setsockopt(client_fd, SOL_SOCKET, SO_REUSEPORT, &flag, sizeof(flag)) < 0) 
    perror("reuse port"); 
#endif 
if(bind(client_fd, (struct sockaddr *)&server_addr, sizeof(server_addr))) 
    perror("bind client fd"); 
if(connect(client_fd, (struct sockaddr *)&client_addr, sizeof(client_addr))) 
    perror("connect client"); 
BIO *cbio = SSL_get_rbio(ssl); 
BIO_set_fd(cbio, client_fd, BIO_NOCLOSE); 
BIO_ctrl(cbio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &client_addr); 
fprintf(stderr, "waiting SSL_accept\n"); 
if(SSL_accept(ssl)!=1){ 
    ERR_print_errors_fp(stderr); 
} 
fprintf(stderr, "SSL_accept completed\n"); 

и код клиента:

SSL_load_error_strings(); 
SSL_library_init(); 
SSL_CTX *ctx = SSL_CTX_new(DTLSv1_client_method()); 
SSL_CTX_set_read_ahead(ctx, 1); 

union { 
    struct sockaddr_storage ss; 
    struct sockaddr_in6 s6; 
    struct sockaddr_in s4; 
} server_addr; 
int fd; 
memset(&server_addr, 0, sizeof(server_addr)); 
if(inet_pton(AF_INET, argv[1], &server_addr.s4.sin_addr) == 1){ 
    fd = socket(AF_INET, SOCK_DGRAM, 0); 
    server_addr.s4.sin_family = AF_INET; 
    server_addr.s4.sin_port = htons(MYPORT); 
}else if(inet_pton(AF_INET6, argv[1], &server_addr.s6.sin6_addr) ==1){ 
    fd = socket(AF_INET6, SOCK_DGRAM, 0); 
    server_addr.s6.sin6_family = AF_INET6; 
    server_addr.s6.sin6_port = htons(MYPORT); 
}else{ 
    fprintf(stderr, "Wrong ip format\n"); 
    return 1; 
} 
if(connect(fd, (struct sockaddr*)&server_addr, sizeof(server_addr))) 
    perror("connect"); 
BIO *bio = BIO_new_dgram(fd, BIO_NOCLOSE); 
BIO_ctrl(bio, BIO_CTRL_DGRAM_SET_CONNECTED, 0, &server_addr); 
SSL *ssl = SSL_new(ctx); 
SSL_set_bio(ssl, bio, bio); 
fprintf(stderr, "waiting SSL_connect\n"); 
if(SSL_connect(ssl)!=1) 
    ERR_print_errors_fp(stderr); 
fprintf(stderr, "SSL connected\n"); 

Это не кажется, нет возврата в SSL_accept и SSL_connect. Я изменил код, изменив sockaddr_in только на sockaddr_in6. версия OpenSSL является: 1.0.2h на Linux

Также я поймал пакеты с Wireshark: enter image description here enter image description here

Может кто-нибудь сказать мне, что случилось с кодом?

+0

У DTLS были некоторые проблемы в 1.0.2 и ниже. Я, кажется, помню, что они обсуждались в списке рассылки OpenSSL и исправлены. [OpenSSL Master] (http://openssl.org/source/gitrepo.html) должен быть в порядке. Я не помню, был ли он перенесен обратно в 1.0.2 и ниже. Сначала я попробую Мастер и посмотрю, устраняет ли проблема. Кроме того, вы можете использовать 's_client' и' s_server' для установления соединения? – jww

+0

@jww Я не могу найти аргумент, чтобы заставить s_sever связывать порт ipv6. И s_client также не удалось подключиться к моему серверу. – choury

ответ

0

добавить

BIO_ctrl_set_connected(bio, 0, &client_addr); 

после DTLSv1_listen в стороне сервера решить эту проблему.

Смежные вопросы