2016-08-04 7 views
1

Ich habe einen Demo-Code von dtls, es funktioniert gut mit ipv4. aber nachdem ich es für IPv6 modifiziert habe, scheitert es im Handshake-Stadium. Der Server-Code wie folgt aus:DTLS Handshake Fehler auf 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"); 

und der Client-Code ist:

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"); 

Es scheint keine Rückkehr in SSL_accept und SSL_connect. Ich habe den Code geändert, indem ich nur sockaddr_in in sockaddr_in6 geändert habe. Die OpenSSL-Version ist: 1.0.2h auf Linux

Auch fing ich die Pakete mit wireshark: enter image description here enter image description here

Kann mir jemand sagen, was mit dem Code falsch?

+0

DTLS hatte einige Probleme in 1.0.2 und darunter. Ich erinnere mich, dass sie auf der OpenSSL-Mailingliste diskutiert und behoben wurden. [OpenSSL Master] (http://openssl.org/source/gitrepo.html) sollte in Ordnung sein. Ich kann mich nicht erinnern, ob es zurück auf 1.0.2 und darunter portiert wurde. Ich würde den Meister zuerst versuchen und sehen, ob es das Problem löscht. Können Sie auch 's_client' und' s_server' verwenden, um eine Verbindung herzustellen? – jww

+0

@jww Ich kann kein arg finden, um s_sever dazu zu bringen, einen ipv6-Port zu binden. Und s_client konnte auch keine Verbindung zu meinem Server herstellen. – choury

Antwort

0

ich hinzufügen

BIO_ctrl_set_connected(bio, 0, &client_addr); 

nach DTLSv1_listen in Server-Seite dieses Problem gelöst.