Fossil SCM

When connecting via a proxy, use the server's own host name, without its port, in the CONNECT request, TLS server name, certificate check etc.

danshearer 2026-10-11 22:21 UTC trunk
Commit 33118a37bd6c360ee77e93dc7e495a15b781fd4e2b1be97ba0cf012d309a4bc8
2 files changed +25 -12 +3
+25 -12
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -379,22 +379,35 @@
379379
BIO_free_all(iBio);
380380
iBio = NULL;
381381
}
382382
socket_close();
383383
}
384
+
385
+/*
386
+** Return the host name of the server that pUrlData connects to, without
387
+** a port number. When the connection goes through a proxy,
388
+** pUrlData->name holds the proxy hostname, and the server hostname is in
389
+** pUrlData->proxyOrigName.
390
+*/
391
+static const char *ssl_server_name(const UrlData *pUrlData){
392
+ return pUrlData->useProxy ? pUrlData->proxyOrigName : pUrlData->name;
393
+}
384394
385395
/* See RFC2817 for details */
386396
static int establish_proxy_tunnel(UrlData *pUrlData, BIO *bio){
387397
int rc, httpVerMin;
388398
char *bbuf;
389399
Blob snd, reply;
390400
int done=0,end=0;
401
+ const char *zHost = ssl_server_name(pUrlData);
402
+ const char *zLb = strchr(zHost, ':') ? "[" : ""; /* IPv6 brackets */
403
+ const char *zRb = zLb[0] ? "]" : "";
391404
blob_zero(&snd);
392
- blob_appendf(&snd, "CONNECT %s:%d HTTP/1.1\r\n", pUrlData->hostname,
393
- pUrlData->proxyOrigPort);
394
- blob_appendf(&snd, "Host: %s:%d\r\n",
395
- pUrlData->hostname, pUrlData->proxyOrigPort);
405
+ blob_appendf(&snd, "CONNECT %s%s%s:%d HTTP/1.1\r\n",
406
+ zLb, zHost, zRb, pUrlData->proxyOrigPort);
407
+ blob_appendf(&snd, "Host: %s%s%s:%d\r\n",
408
+ zLb, zHost, zRb, pUrlData->proxyOrigPort);
396409
if( pUrlData->proxyAuth ){
397410
blob_appendf(&snd, "Proxy-Authorization: %s\r\n", pUrlData->proxyAuth);
398411
}
399412
blob_append(&snd, "Proxy-Connection: keep-alive\r\n", -1);
400413
blob_appendf(&snd, "User-Agent: %s\r\n", get_user_agent());
@@ -507,11 +520,11 @@
507520
BIO_push(iBio, sBio);
508521
BIO_set_ssl(sBio, ssl, BIO_NOCLOSE);
509522
BIO_set_ssl_mode(iBio, 1);
510523
BIO_get_ssl(iBio, &ssl);
511524
512
- zRemoteHost = pUrlData->useProxy ? pUrlData->hostname : pUrlData->name;
525
+ zRemoteHost = ssl_server_name(pUrlData);
513526
isIpAddr = ssl_host_is_ip_address(zRemoteHost);
514527
515528
#if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
516529
if( !isIpAddr && !ssl_host_is_non_ascii(zRemoteHost)
517530
&& !SSL_set_tlsext_host_name(ssl, zRemoteHost)
@@ -606,11 +619,11 @@
606619
BIO_printf(mem, "\n sha256: %s", zHash);
607620
desclen = BIO_get_mem_data(mem, &desc);
608621
609622
prompt = mprintf("Unable to verify SSL cert from %s\n%.*s\n"
610623
"accept this cert and continue (y/N/fingerprint)? ",
611
- pUrlData->name, desclen, desc);
624
+ zRemoteHost, desclen, desc);
612625
BIO_free(mem);
613626
614627
prompt_user(prompt, &ans);
615628
free(prompt);
616629
cReply = blob_str(&ans)[0];
@@ -639,34 +652,34 @@
639652
return 0;
640653
}
641654
642655
/*
643656
** Remember that the cert with the given hash is acceptable for
644
-** use with pUrlData->name.
657
+** use with the server that pUrlData connects to.
645658
*/
646659
LOCAL void ssl_remember_certificate_exception(
647660
UrlData *pUrlData,
648661
const char *zHash
649662
){
650
- db_set_mprintf(zHash, 1, "cert:%s", pUrlData->name);
663
+ db_set_mprintf(zHash, 1, "cert:%s", ssl_server_name(pUrlData));
651664
}
652665
653666
/*
654667
** Return true if the there exists a certificate exception for
655
-** pUrlData->name that matches the hash.
668
+** the server that pUrlData connects to that matches the hash.
656669
*/
657670
LOCAL int ssl_certificate_exception_exists(
658671
UrlData *pUrlData,
659672
const char *zHash
660673
){
661674
char *zName, *zValue;
662
- if( fossil_strcmp(sException.zHost,pUrlData->name)==0
675
+ if( fossil_strcmp(sException.zHost,ssl_server_name(pUrlData))==0
663676
&& fossil_strcmp(sException.zHash,zHash)==0
664677
){
665678
return 1;
666679
}
667
- zName = mprintf("cert:%s", pUrlData->name);
680
+ zName = mprintf("cert:%s", ssl_server_name(pUrlData));
668681
zValue = db_get(zName,0);
669682
fossil_free(zName);
670683
return zValue!=0 && strcmp(zHash,zValue)==0;
671684
}
672685
@@ -676,11 +689,11 @@
676689
LOCAL void ssl_one_time_exception(
677690
UrlData *pUrlData,
678691
const char *zHash
679692
){
680693
fossil_free(sException.zHost);
681
- sException.zHost = fossil_strdup(pUrlData->name);
694
+ sException.zHost = fossil_strdup(ssl_server_name(pUrlData));
682695
fossil_free(sException.zHash);
683696
sException.zHash = fossil_strdup(zHash);
684697
}
685698
686699
/*
687700
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -379,22 +379,35 @@
379 BIO_free_all(iBio);
380 iBio = NULL;
381 }
382 socket_close();
383 }
 
 
 
 
 
 
 
 
 
 
384
385 /* See RFC2817 for details */
386 static int establish_proxy_tunnel(UrlData *pUrlData, BIO *bio){
387 int rc, httpVerMin;
388 char *bbuf;
389 Blob snd, reply;
390 int done=0,end=0;
 
 
 
391 blob_zero(&snd);
392 blob_appendf(&snd, "CONNECT %s:%d HTTP/1.1\r\n", pUrlData->hostname,
393 pUrlData->proxyOrigPort);
394 blob_appendf(&snd, "Host: %s:%d\r\n",
395 pUrlData->hostname, pUrlData->proxyOrigPort);
396 if( pUrlData->proxyAuth ){
397 blob_appendf(&snd, "Proxy-Authorization: %s\r\n", pUrlData->proxyAuth);
398 }
399 blob_append(&snd, "Proxy-Connection: keep-alive\r\n", -1);
400 blob_appendf(&snd, "User-Agent: %s\r\n", get_user_agent());
@@ -507,11 +520,11 @@
507 BIO_push(iBio, sBio);
508 BIO_set_ssl(sBio, ssl, BIO_NOCLOSE);
509 BIO_set_ssl_mode(iBio, 1);
510 BIO_get_ssl(iBio, &ssl);
511
512 zRemoteHost = pUrlData->useProxy ? pUrlData->hostname : pUrlData->name;
513 isIpAddr = ssl_host_is_ip_address(zRemoteHost);
514
515 #if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
516 if( !isIpAddr && !ssl_host_is_non_ascii(zRemoteHost)
517 && !SSL_set_tlsext_host_name(ssl, zRemoteHost)
@@ -606,11 +619,11 @@
606 BIO_printf(mem, "\n sha256: %s", zHash);
607 desclen = BIO_get_mem_data(mem, &desc);
608
609 prompt = mprintf("Unable to verify SSL cert from %s\n%.*s\n"
610 "accept this cert and continue (y/N/fingerprint)? ",
611 pUrlData->name, desclen, desc);
612 BIO_free(mem);
613
614 prompt_user(prompt, &ans);
615 free(prompt);
616 cReply = blob_str(&ans)[0];
@@ -639,34 +652,34 @@
639 return 0;
640 }
641
642 /*
643 ** Remember that the cert with the given hash is acceptable for
644 ** use with pUrlData->name.
645 */
646 LOCAL void ssl_remember_certificate_exception(
647 UrlData *pUrlData,
648 const char *zHash
649 ){
650 db_set_mprintf(zHash, 1, "cert:%s", pUrlData->name);
651 }
652
653 /*
654 ** Return true if the there exists a certificate exception for
655 ** pUrlData->name that matches the hash.
656 */
657 LOCAL int ssl_certificate_exception_exists(
658 UrlData *pUrlData,
659 const char *zHash
660 ){
661 char *zName, *zValue;
662 if( fossil_strcmp(sException.zHost,pUrlData->name)==0
663 && fossil_strcmp(sException.zHash,zHash)==0
664 ){
665 return 1;
666 }
667 zName = mprintf("cert:%s", pUrlData->name);
668 zValue = db_get(zName,0);
669 fossil_free(zName);
670 return zValue!=0 && strcmp(zHash,zValue)==0;
671 }
672
@@ -676,11 +689,11 @@
676 LOCAL void ssl_one_time_exception(
677 UrlData *pUrlData,
678 const char *zHash
679 ){
680 fossil_free(sException.zHost);
681 sException.zHost = fossil_strdup(pUrlData->name);
682 fossil_free(sException.zHash);
683 sException.zHash = fossil_strdup(zHash);
684 }
685
686 /*
687
--- src/http_ssl.c
+++ src/http_ssl.c
@@ -379,22 +379,35 @@
379 BIO_free_all(iBio);
380 iBio = NULL;
381 }
382 socket_close();
383 }
384
385 /*
386 ** Return the host name of the server that pUrlData connects to, without
387 ** a port number. When the connection goes through a proxy,
388 ** pUrlData->name holds the proxy hostname, and the server hostname is in
389 ** pUrlData->proxyOrigName.
390 */
391 static const char *ssl_server_name(const UrlData *pUrlData){
392 return pUrlData->useProxy ? pUrlData->proxyOrigName : pUrlData->name;
393 }
394
395 /* See RFC2817 for details */
396 static int establish_proxy_tunnel(UrlData *pUrlData, BIO *bio){
397 int rc, httpVerMin;
398 char *bbuf;
399 Blob snd, reply;
400 int done=0,end=0;
401 const char *zHost = ssl_server_name(pUrlData);
402 const char *zLb = strchr(zHost, ':') ? "[" : ""; /* IPv6 brackets */
403 const char *zRb = zLb[0] ? "]" : "";
404 blob_zero(&snd);
405 blob_appendf(&snd, "CONNECT %s%s%s:%d HTTP/1.1\r\n",
406 zLb, zHost, zRb, pUrlData->proxyOrigPort);
407 blob_appendf(&snd, "Host: %s%s%s:%d\r\n",
408 zLb, zHost, zRb, pUrlData->proxyOrigPort);
409 if( pUrlData->proxyAuth ){
410 blob_appendf(&snd, "Proxy-Authorization: %s\r\n", pUrlData->proxyAuth);
411 }
412 blob_append(&snd, "Proxy-Connection: keep-alive\r\n", -1);
413 blob_appendf(&snd, "User-Agent: %s\r\n", get_user_agent());
@@ -507,11 +520,11 @@
520 BIO_push(iBio, sBio);
521 BIO_set_ssl(sBio, ssl, BIO_NOCLOSE);
522 BIO_set_ssl_mode(iBio, 1);
523 BIO_get_ssl(iBio, &ssl);
524
525 zRemoteHost = ssl_server_name(pUrlData);
526 isIpAddr = ssl_host_is_ip_address(zRemoteHost);
527
528 #if (SSLEAY_VERSION_NUMBER >= 0x00908070) && !defined(OPENSSL_NO_TLSEXT)
529 if( !isIpAddr && !ssl_host_is_non_ascii(zRemoteHost)
530 && !SSL_set_tlsext_host_name(ssl, zRemoteHost)
@@ -606,11 +619,11 @@
619 BIO_printf(mem, "\n sha256: %s", zHash);
620 desclen = BIO_get_mem_data(mem, &desc);
621
622 prompt = mprintf("Unable to verify SSL cert from %s\n%.*s\n"
623 "accept this cert and continue (y/N/fingerprint)? ",
624 zRemoteHost, desclen, desc);
625 BIO_free(mem);
626
627 prompt_user(prompt, &ans);
628 free(prompt);
629 cReply = blob_str(&ans)[0];
@@ -639,34 +652,34 @@
652 return 0;
653 }
654
655 /*
656 ** Remember that the cert with the given hash is acceptable for
657 ** use with the server that pUrlData connects to.
658 */
659 LOCAL void ssl_remember_certificate_exception(
660 UrlData *pUrlData,
661 const char *zHash
662 ){
663 db_set_mprintf(zHash, 1, "cert:%s", ssl_server_name(pUrlData));
664 }
665
666 /*
667 ** Return true if the there exists a certificate exception for
668 ** the server that pUrlData connects to that matches the hash.
669 */
670 LOCAL int ssl_certificate_exception_exists(
671 UrlData *pUrlData,
672 const char *zHash
673 ){
674 char *zName, *zValue;
675 if( fossil_strcmp(sException.zHost,ssl_server_name(pUrlData))==0
676 && fossil_strcmp(sException.zHash,zHash)==0
677 ){
678 return 1;
679 }
680 zName = mprintf("cert:%s", ssl_server_name(pUrlData));
681 zValue = db_get(zName,0);
682 fossil_free(zName);
683 return zValue!=0 && strcmp(zHash,zValue)==0;
684 }
685
@@ -676,11 +689,11 @@
689 LOCAL void ssl_one_time_exception(
690 UrlData *pUrlData,
691 const char *zHash
692 ){
693 fossil_free(sException.zHost);
694 sException.zHost = fossil_strdup(ssl_server_name(pUrlData));
695 fossil_free(sException.zHash);
696 sException.zHash = fossil_strdup(zHash);
697 }
698
699 /*
700
+3
--- src/url.c
+++ src/url.c
@@ -63,10 +63,11 @@
6363
char *subpath; /* Secondary HTTP request path for ssh: and file: */
6464
char *pwConfig; /* CONFIG table entry that gave us the password */
6565
unsigned flags; /* Boolean flags controlling URL processing */
6666
int useProxy; /* Used to remember that a proxy is in use */
6767
int proxyOrigPort; /* Tunneled port number for https through proxy */
68
+ char *proxyOrigName; /* Tunneled host name for https through proxy */
6869
char *proxyUrlPath; /* Remember path when proxy is use */
6970
char *proxyUrlCanonical; /* Remember canonical path when proxy is use */
7071
};
7172
#endif /* INTERFACE */
7273
@@ -627,10 +628,11 @@
627628
}
628629
if( zProxy && zProxy[0] && !is_false(zProxy)
629630
&& !g.url.isSsh && !g.url.isFile ){
630631
char *zOriginalUrl = g.url.canonical;
631632
char *zOriginalHost = g.url.hostname;
633
+ char *zOriginalName = g.url.name;
632634
int fOriginalIsHttps = g.url.isHttps;
633635
char *zOriginalUser = g.url.user;
634636
char *zOriginalPasswd = g.url.passwd;
635637
char *zOriginalUrlPath = g.url.path;
636638
int iOriginalPort = g.url.port;
@@ -652,10 +654,11 @@
652654
g.url.isHttps = fOriginalIsHttps;
653655
g.url.useProxy = 1;
654656
g.url.proxyUrlCanonical = zOriginalUrl;;
655657
g.url.proxyUrlPath = zOriginalUrlPath;
656658
g.url.proxyOrigPort = iOriginalPort;
659
+ g.url.proxyOrigName = zOriginalName;
657660
g.url.flags = uOriginalFlags;
658661
}
659662
}
660663
661664
#if INTERFACE
662665
--- src/url.c
+++ src/url.c
@@ -63,10 +63,11 @@
63 char *subpath; /* Secondary HTTP request path for ssh: and file: */
64 char *pwConfig; /* CONFIG table entry that gave us the password */
65 unsigned flags; /* Boolean flags controlling URL processing */
66 int useProxy; /* Used to remember that a proxy is in use */
67 int proxyOrigPort; /* Tunneled port number for https through proxy */
 
68 char *proxyUrlPath; /* Remember path when proxy is use */
69 char *proxyUrlCanonical; /* Remember canonical path when proxy is use */
70 };
71 #endif /* INTERFACE */
72
@@ -627,10 +628,11 @@
627 }
628 if( zProxy && zProxy[0] && !is_false(zProxy)
629 && !g.url.isSsh && !g.url.isFile ){
630 char *zOriginalUrl = g.url.canonical;
631 char *zOriginalHost = g.url.hostname;
 
632 int fOriginalIsHttps = g.url.isHttps;
633 char *zOriginalUser = g.url.user;
634 char *zOriginalPasswd = g.url.passwd;
635 char *zOriginalUrlPath = g.url.path;
636 int iOriginalPort = g.url.port;
@@ -652,10 +654,11 @@
652 g.url.isHttps = fOriginalIsHttps;
653 g.url.useProxy = 1;
654 g.url.proxyUrlCanonical = zOriginalUrl;;
655 g.url.proxyUrlPath = zOriginalUrlPath;
656 g.url.proxyOrigPort = iOriginalPort;
 
657 g.url.flags = uOriginalFlags;
658 }
659 }
660
661 #if INTERFACE
662
--- src/url.c
+++ src/url.c
@@ -63,10 +63,11 @@
63 char *subpath; /* Secondary HTTP request path for ssh: and file: */
64 char *pwConfig; /* CONFIG table entry that gave us the password */
65 unsigned flags; /* Boolean flags controlling URL processing */
66 int useProxy; /* Used to remember that a proxy is in use */
67 int proxyOrigPort; /* Tunneled port number for https through proxy */
68 char *proxyOrigName; /* Tunneled host name for https through proxy */
69 char *proxyUrlPath; /* Remember path when proxy is use */
70 char *proxyUrlCanonical; /* Remember canonical path when proxy is use */
71 };
72 #endif /* INTERFACE */
73
@@ -627,10 +628,11 @@
628 }
629 if( zProxy && zProxy[0] && !is_false(zProxy)
630 && !g.url.isSsh && !g.url.isFile ){
631 char *zOriginalUrl = g.url.canonical;
632 char *zOriginalHost = g.url.hostname;
633 char *zOriginalName = g.url.name;
634 int fOriginalIsHttps = g.url.isHttps;
635 char *zOriginalUser = g.url.user;
636 char *zOriginalPasswd = g.url.passwd;
637 char *zOriginalUrlPath = g.url.path;
638 int iOriginalPort = g.url.port;
@@ -652,10 +654,11 @@
654 g.url.isHttps = fOriginalIsHttps;
655 g.url.useProxy = 1;
656 g.url.proxyUrlCanonical = zOriginalUrl;;
657 g.url.proxyUrlPath = zOriginalUrlPath;
658 g.url.proxyOrigPort = iOriginalPort;
659 g.url.proxyOrigName = zOriginalName;
660 g.url.flags = uOriginalFlags;
661 }
662 }
663
664 #if INTERFACE
665

Keyboard Shortcuts

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