Fossil SCM

Update client-side handling of HTTPS urls to better handle IPv6 by first opening a socket and then upgrading it to TLS.

andybradford 2025-12-21 23:03 trunk merge
Commit f39c525448efe8fed0671d77afb00d6f5cc907157f3aa626e783429354532ad7
2 files changed +7 +20 -99
--- src/http_socket.c
+++ src/http_socket.c
@@ -87,10 +87,17 @@
8787
char *socket_errmsg(void){
8888
char *zResult = socketErrMsg;
8989
socketErrMsg = 0;
9090
return zResult;
9191
}
92
+
93
+/*
94
+** Return the file descriptor for the open socket.
95
+*/
96
+int socket_get_fd(){
97
+ return iSocket;
98
+}
9299
93100
/*
94101
** Call this routine once before any other use of the socket interface.
95102
** This routine does initial configuration of the socket module.
96103
*/
97104
--- src/http_socket.c
+++ src/http_socket.c
@@ -87,10 +87,17 @@
87 char *socket_errmsg(void){
88 char *zResult = socketErrMsg;
89 socketErrMsg = 0;
90 return zResult;
91 }
 
 
 
 
 
 
 
92
93 /*
94 ** Call this routine once before any other use of the socket interface.
95 ** This routine does initial configuration of the socket module.
96 */
97
--- src/http_socket.c
+++ src/http_socket.c
@@ -87,10 +87,17 @@
87 char *socket_errmsg(void){
88 char *zResult = socketErrMsg;
89 socketErrMsg = 0;
90 return zResult;
91 }
92
93 /*
94 ** Return the file descriptor for the open socket.
95 */
96 int socket_get_fd(){
97 return iSocket;
98 }
99
100 /*
101 ** Call this routine once before any other use of the socket interface.
102 ** This routine does initial configuration of the socket module.
103 */
104
+20 -99
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -363,10 +363,11 @@
363363
if( sslIsInit ){
364364
SSL_CTX_free(sslCtx);
365365
ssl_clear_errmsg();
366366
sslIsInit = 0;
367367
}
368
+ socket_global_shutdown();
368369
}
369370
370371
/*
371372
** Close the currently open client SSL connection. If no connection is open,
372373
** this routine is a no-op.
@@ -375,10 +376,11 @@
375376
if( iBio!=NULL ){
376377
(void)BIO_reset(iBio);
377378
BIO_free_all(iBio);
378379
iBio = NULL;
379380
}
381
+ socket_close();
380382
}
381383
382384
/* See RFC2817 for details */
383385
static int establish_proxy_tunnel(UrlData *pUrlData, BIO *bio){
384386
int rc, httpVerMin;
@@ -450,63 +452,35 @@
450452
** Return the number of errors.
451453
*/
452454
int ssl_open_client(UrlData *pUrlData){
453455
X509 *cert;
454456
const char *zRemoteHost;
457
+ BIO *sBio;
455458
456459
ssl_global_init_client();
460
+ if( socket_open(pUrlData) ){
461
+ ssl_set_errmsg("SSL: cannot open socket (%s)", socket_errmsg());
462
+ return 1;
463
+ }
464
+ sBio = BIO_new_socket(socket_get_fd(), 0);
457465
if( pUrlData->useProxy ){
458
- int rc;
459
- char *connStr = mprintf("%s:%d", g.url.name, pUrlData->port);
460
- BIO *sBio = BIO_new_connect(connStr);
461
- switch( g.eIPvers ){
462
- default: /* Any available protocol */
463
- break;
464
- case 1: /* IPv4 only */
465
-#ifdef BIO_FAMILY_IPV4
466
- BIO_set_conn_ip_family(sBio, BIO_FAMILY_IPV4);
467
-#else
468
- fossil_warning("The --ipv4 option is not supported in this build\n");
469
-#endif
470
- break;
471
- case 2: /* IPv6 only */
472
-#ifdef BIO_FAMILY_IPV6
473
- BIO_set_conn_ip_family(sBio, BIO_FAMILY_IPV6);
474
-#else
475
- fossil_warning("The --ipv6 option is not supported in this build\n");
476
-#endif
477
- break;
478
- }
479
- fossil_free(connStr);
480
- if( BIO_do_connect(sBio)<=0 ){
481
- ssl_set_errmsg("SSL: cannot connect to proxy %s:%d (%s)",
482
- pUrlData->name, pUrlData->port,
483
- ERR_reason_error_string(ERR_get_error()));
484
- ssl_close_client();
485
- return 1;
486
- }
487
- rc = establish_proxy_tunnel(pUrlData, sBio);
466
+ int rc = establish_proxy_tunnel(pUrlData, sBio);
488467
if( rc<200||rc>299 ){
489468
ssl_set_errmsg("SSL: proxy connect failed with HTTP status code %d", rc);
469
+ ssl_close_client();
490470
return 1;
491471
}
492472
493473
pUrlData->path = pUrlData->proxyUrlPath;
494
-
495
- iBio = BIO_new_ssl(sslCtx, 1);
496
- BIO_push(iBio, sBio);
497
- zRemoteHost = pUrlData->hostname;
498
- }else{
499
- iBio = BIO_new_ssl_connect(sslCtx);
500
- zRemoteHost = pUrlData->name;
501
- }
502
- if( iBio==NULL ) {
503
- ssl_set_errmsg("SSL: cannot open SSL (%s)",
504
- ERR_reason_error_string(ERR_get_error()));
505
- return 1;
506
- }
474
+ }
475
+ iBio = BIO_new_ssl(sslCtx, 1);
476
+ BIO_push(iBio, sBio);
477
+ BIO_set_ssl(sBio, ssl, BIO_NOCLOSE);
478
+ BIO_set_ssl_mode(iBio, 1);
507479
BIO_get_ssl(iBio, &ssl);
480
+
481
+ zRemoteHost = pUrlData->useProxy ? pUrlData->hostname : pUrlData->name;
508482
509483
#if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
510484
if( !SSL_set_tlsext_host_name(ssl, zRemoteHost)){
511485
fossil_warning("WARNING: failed to set server name indication (SNI), "
512486
"continuing without it.\n");
@@ -523,45 +497,14 @@
523497
}
524498
/* SSL_set_verify(ssl, SSL_VERIFY_PEER, 0); */
525499
}
526500
#endif
527501
528
- if( !pUrlData->useProxy ){
529
- char *connStr = mprintf("%s:%d", pUrlData->name, pUrlData->port);
530
- BIO_set_conn_hostname(iBio, connStr);
531
- fossil_free(connStr);
532
- switch( g.eIPvers ){
533
- default: /* Any available protocol */
534
- break;
535
- case 1: /* IPv4 only */
536
-#ifdef BIO_FAMILY_IPV4
537
- BIO_set_conn_ip_family(iBio, BIO_FAMILY_IPV4);
538
-#else
539
- fossil_warning("The --ipv4 option is not supported in this build\n");
540
-#endif
541
- break;
542
- case 2: /* IPv6 only */
543
-#ifdef BIO_FAMILY_IPV6
544
- BIO_set_conn_ip_family(iBio, BIO_FAMILY_IPV6);
545
-#else
546
- fossil_warning("The --ipv6 option is not supported in this build\n");
547
-#endif
548
- break;
549
- }
550
- if( BIO_do_connect(iBio)<=0 ){
551
- ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)",
552
- pUrlData->name, pUrlData->port,
553
- ERR_reason_error_string(ERR_get_error()));
554
- ssl_close_client();
555
- return 1;
556
- }
557
- }
558
-
559
- if( BIO_do_handshake(iBio)<=0 ) {
502
+ if( BIO_do_handshake(iBio)<=0 ){
560503
ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)",
561
- pUrlData->useProxy?pUrlData->hostname:pUrlData->name,
562
- pUrlData->useProxy?pUrlData->proxyOrigPort:pUrlData->port,
504
+ zRemoteHost,
505
+ pUrlData->useProxy ? pUrlData->proxyOrigPort : pUrlData->port,
563506
ERR_reason_error_string(ERR_get_error()));
564507
ssl_close_client();
565508
return 1;
566509
}
567510
/* Check if certificate is valid */
@@ -651,32 +594,10 @@
651594
}
652595
blob_reset(&ans);
653596
}
654597
}
655598
656
- /* Set the Global.zIpAddr variable to the server we are talking to.
657
- ** This is used to populate the ipaddr column of the rcvfrom table,
658
- ** if any files are received from the server.
659
- */
660
- {
661
- /* As soon as libressl implements
662
- ** BIO_ADDR_hostname_string/BIO_get_conn_address.
663
- ** check here for the correct LIBRESSL_VERSION_NUMBER too. For now: disable
664
- */
665
-#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L \
666
- && !defined(LIBRESSL_VERSION_NUMBER)
667
- char *ip = BIO_ADDR_hostname_string(BIO_get_conn_address(iBio),1);
668
- g.zIpAddr = fossil_strdup(ip);
669
- OPENSSL_free(ip);
670
-#else
671
- /* IPv4 only code */
672
- const unsigned char *ip;
673
- ip = (const unsigned char*)BIO_ptr_ctrl(iBio,BIO_C_GET_CONNECT,2);
674
- g.zIpAddr = mprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
675
-#endif
676
- }
677
-
678599
X509_free(cert);
679600
return 0;
680601
}
681602
682603
/*
683604
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -363,10 +363,11 @@
363 if( sslIsInit ){
364 SSL_CTX_free(sslCtx);
365 ssl_clear_errmsg();
366 sslIsInit = 0;
367 }
 
368 }
369
370 /*
371 ** Close the currently open client SSL connection. If no connection is open,
372 ** this routine is a no-op.
@@ -375,10 +376,11 @@
375 if( iBio!=NULL ){
376 (void)BIO_reset(iBio);
377 BIO_free_all(iBio);
378 iBio = NULL;
379 }
 
380 }
381
382 /* See RFC2817 for details */
383 static int establish_proxy_tunnel(UrlData *pUrlData, BIO *bio){
384 int rc, httpVerMin;
@@ -450,63 +452,35 @@
450 ** Return the number of errors.
451 */
452 int ssl_open_client(UrlData *pUrlData){
453 X509 *cert;
454 const char *zRemoteHost;
 
455
456 ssl_global_init_client();
 
 
 
 
 
457 if( pUrlData->useProxy ){
458 int rc;
459 char *connStr = mprintf("%s:%d", g.url.name, pUrlData->port);
460 BIO *sBio = BIO_new_connect(connStr);
461 switch( g.eIPvers ){
462 default: /* Any available protocol */
463 break;
464 case 1: /* IPv4 only */
465 #ifdef BIO_FAMILY_IPV4
466 BIO_set_conn_ip_family(sBio, BIO_FAMILY_IPV4);
467 #else
468 fossil_warning("The --ipv4 option is not supported in this build\n");
469 #endif
470 break;
471 case 2: /* IPv6 only */
472 #ifdef BIO_FAMILY_IPV6
473 BIO_set_conn_ip_family(sBio, BIO_FAMILY_IPV6);
474 #else
475 fossil_warning("The --ipv6 option is not supported in this build\n");
476 #endif
477 break;
478 }
479 fossil_free(connStr);
480 if( BIO_do_connect(sBio)<=0 ){
481 ssl_set_errmsg("SSL: cannot connect to proxy %s:%d (%s)",
482 pUrlData->name, pUrlData->port,
483 ERR_reason_error_string(ERR_get_error()));
484 ssl_close_client();
485 return 1;
486 }
487 rc = establish_proxy_tunnel(pUrlData, sBio);
488 if( rc<200||rc>299 ){
489 ssl_set_errmsg("SSL: proxy connect failed with HTTP status code %d", rc);
 
490 return 1;
491 }
492
493 pUrlData->path = pUrlData->proxyUrlPath;
494
495 iBio = BIO_new_ssl(sslCtx, 1);
496 BIO_push(iBio, sBio);
497 zRemoteHost = pUrlData->hostname;
498 }else{
499 iBio = BIO_new_ssl_connect(sslCtx);
500 zRemoteHost = pUrlData->name;
501 }
502 if( iBio==NULL ) {
503 ssl_set_errmsg("SSL: cannot open SSL (%s)",
504 ERR_reason_error_string(ERR_get_error()));
505 return 1;
506 }
507 BIO_get_ssl(iBio, &ssl);
 
 
508
509 #if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
510 if( !SSL_set_tlsext_host_name(ssl, zRemoteHost)){
511 fossil_warning("WARNING: failed to set server name indication (SNI), "
512 "continuing without it.\n");
@@ -523,45 +497,14 @@
523 }
524 /* SSL_set_verify(ssl, SSL_VERIFY_PEER, 0); */
525 }
526 #endif
527
528 if( !pUrlData->useProxy ){
529 char *connStr = mprintf("%s:%d", pUrlData->name, pUrlData->port);
530 BIO_set_conn_hostname(iBio, connStr);
531 fossil_free(connStr);
532 switch( g.eIPvers ){
533 default: /* Any available protocol */
534 break;
535 case 1: /* IPv4 only */
536 #ifdef BIO_FAMILY_IPV4
537 BIO_set_conn_ip_family(iBio, BIO_FAMILY_IPV4);
538 #else
539 fossil_warning("The --ipv4 option is not supported in this build\n");
540 #endif
541 break;
542 case 2: /* IPv6 only */
543 #ifdef BIO_FAMILY_IPV6
544 BIO_set_conn_ip_family(iBio, BIO_FAMILY_IPV6);
545 #else
546 fossil_warning("The --ipv6 option is not supported in this build\n");
547 #endif
548 break;
549 }
550 if( BIO_do_connect(iBio)<=0 ){
551 ssl_set_errmsg("SSL: cannot connect to host %s:%d (%s)",
552 pUrlData->name, pUrlData->port,
553 ERR_reason_error_string(ERR_get_error()));
554 ssl_close_client();
555 return 1;
556 }
557 }
558
559 if( BIO_do_handshake(iBio)<=0 ) {
560 ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)",
561 pUrlData->useProxy?pUrlData->hostname:pUrlData->name,
562 pUrlData->useProxy?pUrlData->proxyOrigPort:pUrlData->port,
563 ERR_reason_error_string(ERR_get_error()));
564 ssl_close_client();
565 return 1;
566 }
567 /* Check if certificate is valid */
@@ -651,32 +594,10 @@
651 }
652 blob_reset(&ans);
653 }
654 }
655
656 /* Set the Global.zIpAddr variable to the server we are talking to.
657 ** This is used to populate the ipaddr column of the rcvfrom table,
658 ** if any files are received from the server.
659 */
660 {
661 /* As soon as libressl implements
662 ** BIO_ADDR_hostname_string/BIO_get_conn_address.
663 ** check here for the correct LIBRESSL_VERSION_NUMBER too. For now: disable
664 */
665 #if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L \
666 && !defined(LIBRESSL_VERSION_NUMBER)
667 char *ip = BIO_ADDR_hostname_string(BIO_get_conn_address(iBio),1);
668 g.zIpAddr = fossil_strdup(ip);
669 OPENSSL_free(ip);
670 #else
671 /* IPv4 only code */
672 const unsigned char *ip;
673 ip = (const unsigned char*)BIO_ptr_ctrl(iBio,BIO_C_GET_CONNECT,2);
674 g.zIpAddr = mprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
675 #endif
676 }
677
678 X509_free(cert);
679 return 0;
680 }
681
682 /*
683
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -363,10 +363,11 @@
363 if( sslIsInit ){
364 SSL_CTX_free(sslCtx);
365 ssl_clear_errmsg();
366 sslIsInit = 0;
367 }
368 socket_global_shutdown();
369 }
370
371 /*
372 ** Close the currently open client SSL connection. If no connection is open,
373 ** this routine is a no-op.
@@ -375,10 +376,11 @@
376 if( iBio!=NULL ){
377 (void)BIO_reset(iBio);
378 BIO_free_all(iBio);
379 iBio = NULL;
380 }
381 socket_close();
382 }
383
384 /* See RFC2817 for details */
385 static int establish_proxy_tunnel(UrlData *pUrlData, BIO *bio){
386 int rc, httpVerMin;
@@ -450,63 +452,35 @@
452 ** Return the number of errors.
453 */
454 int ssl_open_client(UrlData *pUrlData){
455 X509 *cert;
456 const char *zRemoteHost;
457 BIO *sBio;
458
459 ssl_global_init_client();
460 if( socket_open(pUrlData) ){
461 ssl_set_errmsg("SSL: cannot open socket (%s)", socket_errmsg());
462 return 1;
463 }
464 sBio = BIO_new_socket(socket_get_fd(), 0);
465 if( pUrlData->useProxy ){
466 int rc = establish_proxy_tunnel(pUrlData, sBio);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
467 if( rc<200||rc>299 ){
468 ssl_set_errmsg("SSL: proxy connect failed with HTTP status code %d", rc);
469 ssl_close_client();
470 return 1;
471 }
472
473 pUrlData->path = pUrlData->proxyUrlPath;
474 }
475 iBio = BIO_new_ssl(sslCtx, 1);
476 BIO_push(iBio, sBio);
477 BIO_set_ssl(sBio, ssl, BIO_NOCLOSE);
478 BIO_set_ssl_mode(iBio, 1);
 
 
 
 
 
 
 
 
479 BIO_get_ssl(iBio, &ssl);
480
481 zRemoteHost = pUrlData->useProxy ? pUrlData->hostname : pUrlData->name;
482
483 #if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
484 if( !SSL_set_tlsext_host_name(ssl, zRemoteHost)){
485 fossil_warning("WARNING: failed to set server name indication (SNI), "
486 "continuing without it.\n");
@@ -523,45 +497,14 @@
497 }
498 /* SSL_set_verify(ssl, SSL_VERIFY_PEER, 0); */
499 }
500 #endif
501
502 if( BIO_do_handshake(iBio)<=0 ){
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
503 ssl_set_errmsg("Error establishing SSL connection %s:%d (%s)",
504 zRemoteHost,
505 pUrlData->useProxy ? pUrlData->proxyOrigPort : pUrlData->port,
506 ERR_reason_error_string(ERR_get_error()));
507 ssl_close_client();
508 return 1;
509 }
510 /* Check if certificate is valid */
@@ -651,32 +594,10 @@
594 }
595 blob_reset(&ans);
596 }
597 }
598
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
599 X509_free(cert);
600 return 0;
601 }
602
603 /*
604

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button