mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
Issue 1447: Pass proper Host header and SNI when SRV is used with curl.
* configure.ac: Check for inet_ntop. * m4/libcurl.m4: Provide a #define for the version of the curl library. * keyserver/gpgkeys_hkp.c (main, srv_replace): Call getaddrinfo() on each target. Once we find one that resolves to an address (whether IPv4 or IPv6), pass it into libcurl via CURLOPT_RESOLVE using the SRV name as the "host". Force the HTTP Host header to be the same. Backported from 6b1f71055ebab36989e2089cfde319d2ba40ada7 * keyserver/gpgkeys_hkp.c (main): Only default try-dns-srv to on if we have SRV support in the first place. Backported from 732f3d1d4786239db5f31f82cc04ec79326cc13c
This commit is contained in:
parent
6c3a76cca0
commit
5c557a51cd
@ -1021,7 +1021,7 @@ AC_CHECK_FUNCS(strcasecmp strncasecmp ctermid times unsetenv getpwnam getpwuid)
|
|||||||
AC_CHECK_FUNCS(memmove gettimeofday getrusage setrlimit clock_gettime)
|
AC_CHECK_FUNCS(memmove gettimeofday getrusage setrlimit clock_gettime)
|
||||||
AC_CHECK_FUNCS(atexit raise getpagesize strftime nl_langinfo setlocale)
|
AC_CHECK_FUNCS(atexit raise getpagesize strftime nl_langinfo setlocale)
|
||||||
AC_CHECK_FUNCS(waitpid wait4 sigaction sigprocmask rand pipe stat getaddrinfo)
|
AC_CHECK_FUNCS(waitpid wait4 sigaction sigprocmask rand pipe stat getaddrinfo)
|
||||||
AC_CHECK_FUNCS(fcntl ftruncate)
|
AC_CHECK_FUNCS(fcntl ftruncate inet_ntop)
|
||||||
AC_REPLACE_FUNCS(mkdtemp timegm isascii memrchr strsep)
|
AC_REPLACE_FUNCS(mkdtemp timegm isascii memrchr strsep)
|
||||||
|
|
||||||
AC_CHECK_TYPES([struct sigaction, sigset_t],,,[#include <signal.h>])
|
AC_CHECK_TYPES([struct sigaction, sigset_t],,,[#include <signal.h>])
|
||||||
|
@ -40,6 +40,20 @@
|
|||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LIBCURL
|
#ifdef HAVE_LIBCURL
|
||||||
# include <curl/curl.h>
|
# include <curl/curl.h>
|
||||||
|
/* This #define rigamarole is to enable a hack to fake DNS SRV using
|
||||||
|
libcurl. It only works if we have getaddrinfo(), inet_ntop(), and
|
||||||
|
a modern enough version of libcurl (7.21.3) so we can use
|
||||||
|
CURLOPT_RESOLVE to feed the resolver from the outside to force
|
||||||
|
libcurl to pass the right SNI. */
|
||||||
|
#if (defined(HAVE_GETADDRINFO) && defined(HAVE_INET_NTOP) \
|
||||||
|
&& LIBCURL_VERNUM >= 0x071503)
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <sys/socket.h>
|
||||||
|
# include <netdb.h>
|
||||||
|
# include <arpa/inet.h>
|
||||||
|
#else
|
||||||
|
# undef USE_DNS_SRV
|
||||||
|
#endif
|
||||||
#else
|
#else
|
||||||
# include "curl-shim.h"
|
# include "curl-shim.h"
|
||||||
#endif
|
#endif
|
||||||
@ -62,7 +76,8 @@ static char *proto,*port;
|
|||||||
static size_t
|
static size_t
|
||||||
curl_mrindex_writer(const void *ptr,size_t size,size_t nmemb,void *stream)
|
curl_mrindex_writer(const void *ptr,size_t size,size_t nmemb,void *stream)
|
||||||
{
|
{
|
||||||
static int checked=0,swallow=0;
|
static int checked=0;
|
||||||
|
static int swallow=0;
|
||||||
|
|
||||||
if(!checked)
|
if(!checked)
|
||||||
{
|
{
|
||||||
@ -496,18 +511,29 @@ fail_all(struct keylist *keylist,int err)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_LIBCURL
|
#if defined(HAVE_LIBCURL) && defined(USE_DNS_SRV)
|
||||||
/* If there is a SRV record, take the highest ranked possibility.
|
/* If there is a SRV record, take the highest ranked possibility.
|
||||||
This is a hack, as we don't proceed downwards. */
|
This is a hack, as we don't proceed downwards if we can't
|
||||||
|
connect(), but only if we can't getaddinfo(). All this should
|
||||||
|
ideally be replaced by actual SRV support in libcurl someday! */
|
||||||
|
|
||||||
|
#define HOST_HEADER "Host:"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
srv_replace(const char *srvtag)
|
srv_replace(const char *srvtag,
|
||||||
|
struct curl_slist **headers, struct curl_slist **resolve)
|
||||||
{
|
{
|
||||||
#ifdef USE_DNS_SRV
|
|
||||||
struct srventry *srvlist=NULL;
|
struct srventry *srvlist=NULL;
|
||||||
|
int srvcount, srvindex;
|
||||||
|
char *portstr;
|
||||||
|
|
||||||
if(!srvtag)
|
if(!srvtag)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
portstr=malloc (MAX_PORT);
|
||||||
|
if(!portstr)
|
||||||
|
return;
|
||||||
|
|
||||||
if(1+strlen(srvtag)+6+strlen(opt->host)+1<=MAXDNAME)
|
if(1+strlen(srvtag)+6+strlen(opt->host)+1<=MAXDNAME)
|
||||||
{
|
{
|
||||||
char srvname[MAXDNAME];
|
char srvname[MAXDNAME];
|
||||||
@ -516,30 +542,78 @@ srv_replace(const char *srvtag)
|
|||||||
strcat(srvname,srvtag);
|
strcat(srvname,srvtag);
|
||||||
strcat(srvname,"._tcp.");
|
strcat(srvname,"._tcp.");
|
||||||
strcat(srvname,opt->host);
|
strcat(srvname,opt->host);
|
||||||
getsrv(srvname,&srvlist);
|
srvcount=getsrv(srvname,&srvlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(srvlist)
|
for(srvindex=0 ; srvindex<srvcount && portstr ; srvindex++)
|
||||||
{
|
{
|
||||||
char *newname,*newport;
|
struct addrinfo hints, *res;
|
||||||
|
|
||||||
newname=strdup(srvlist->target);
|
sprintf (portstr, "%hu", srvlist[srvindex].port);
|
||||||
newport=xtrymalloc(MAX_PORT);
|
memset (&hints, 0, sizeof (hints));
|
||||||
if(newname && newport)
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
|
||||||
|
if (getaddrinfo (srvlist[srvindex].target, portstr, &hints, &res) == 0)
|
||||||
{
|
{
|
||||||
free(opt->host);
|
/* Very safe */
|
||||||
|
char ipaddr[INET_ADDRSTRLEN+INET6_ADDRSTRLEN];
|
||||||
|
|
||||||
|
if((res->ai_family==AF_INET
|
||||||
|
&& inet_ntop (res->ai_family,
|
||||||
|
&((struct sockaddr_in *)res->ai_addr)->sin_addr,
|
||||||
|
ipaddr,sizeof(ipaddr)))
|
||||||
|
|| (res->ai_family==AF_INET6
|
||||||
|
&& inet_ntop (res->ai_family,
|
||||||
|
&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr,
|
||||||
|
ipaddr,sizeof(ipaddr))))
|
||||||
|
{
|
||||||
|
char *entry,*host;
|
||||||
|
|
||||||
|
entry=malloc (strlen(opt->host)+1
|
||||||
|
+strlen(portstr)+1+strlen(ipaddr)+1);
|
||||||
|
|
||||||
|
host=malloc (strlen(HOST_HEADER)+1+strlen(opt->host)+1);
|
||||||
|
|
||||||
|
if(entry && host)
|
||||||
|
{
|
||||||
|
sprintf (entry, "%s:%s:%s", opt->host, portstr, ipaddr);
|
||||||
|
sprintf (host, "%s %s", HOST_HEADER, opt->host);
|
||||||
|
|
||||||
|
*resolve=curl_slist_append (*resolve,entry);
|
||||||
|
*headers=curl_slist_append (*headers,host);
|
||||||
|
|
||||||
|
if(*resolve && *headers)
|
||||||
|
{
|
||||||
|
if(curl_easy_setopt (curl,
|
||||||
|
CURLOPT_RESOLVE,*resolve)==CURLE_OK)
|
||||||
|
|
||||||
|
{
|
||||||
|
if(opt->debug)
|
||||||
|
fprintf (console, "gpgkeys: Faking %s SRV from"
|
||||||
|
" %s to %s:%u\n",
|
||||||
|
srvtag, opt->host,
|
||||||
|
srvlist[srvindex].target,
|
||||||
|
srvlist[srvindex].port);
|
||||||
|
|
||||||
free (opt->port);
|
free (opt->port);
|
||||||
opt->host=newname;
|
opt->port=portstr;
|
||||||
snprintf(newport,MAX_PORT,"%u",srvlist->port);
|
portstr=NULL;
|
||||||
opt->port=newport;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free (entry);
|
||||||
|
free (host);
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo (res);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
continue; /* Not found */
|
||||||
free(newname);
|
|
||||||
free(newport);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
#endif
|
free (srvlist);
|
||||||
|
free (portstr);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -555,12 +629,20 @@ show_help (FILE *fp)
|
|||||||
int
|
int
|
||||||
main(int argc,char *argv[])
|
main(int argc,char *argv[])
|
||||||
{
|
{
|
||||||
int arg,ret=KEYSERVER_INTERNAL_ERROR,try_srv=1;
|
int arg,ret=KEYSERVER_INTERNAL_ERROR;
|
||||||
char line[MAX_LINE];
|
char line[MAX_LINE];
|
||||||
int failed=0;
|
int failed=0;
|
||||||
struct keylist *keylist=NULL,*keyptr=NULL;
|
struct keylist *keylist=NULL,*keyptr=NULL;
|
||||||
char *proxy=NULL;
|
char *proxy=NULL;
|
||||||
struct curl_slist *headers=NULL;
|
struct curl_slist *headers=NULL;
|
||||||
|
struct curl_slist *resolve=NULL;
|
||||||
|
|
||||||
|
/* Only default this to on if we have SRV support */
|
||||||
|
#ifdef USE_DNS_SRV
|
||||||
|
int try_srv = 1;
|
||||||
|
#else
|
||||||
|
int try_srv = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
console=stderr;
|
console=stderr;
|
||||||
|
|
||||||
@ -723,6 +805,13 @@ main(int argc,char *argv[])
|
|||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(opt->debug)
|
||||||
|
{
|
||||||
|
fprintf(console,"gpgkeys: curl version = %s\n",curl_version());
|
||||||
|
curl_easy_setopt(curl,CURLOPT_STDERR,console);
|
||||||
|
curl_easy_setopt(curl,CURLOPT_VERBOSE,1L);
|
||||||
|
}
|
||||||
|
|
||||||
/* Only use SRV if the user does not provide a :port. The semantics
|
/* Only use SRV if the user does not provide a :port. The semantics
|
||||||
of a specified port and SRV do not play well together. */
|
of a specified port and SRV do not play well together. */
|
||||||
if(!opt->port && try_srv)
|
if(!opt->port && try_srv)
|
||||||
@ -741,8 +830,12 @@ main(int argc,char *argv[])
|
|||||||
This isn't as good as true SRV support, as we do not try all
|
This isn't as good as true SRV support, as we do not try all
|
||||||
possible targets at one particular level and work our way
|
possible targets at one particular level and work our way
|
||||||
down the list, but it's better than nothing. */
|
down the list, but it's better than nothing. */
|
||||||
srv_replace(srvtag);
|
#ifdef USE_DNS_SRV
|
||||||
|
srv_replace(srvtag,&headers,&resolve);
|
||||||
#else
|
#else
|
||||||
|
fprintf(console,"gpgkeys: try-dns-srv was requested, but not SRV capable\n");
|
||||||
|
#endif
|
||||||
|
#else /* !HAVE_LIBCURL */
|
||||||
/* We're using our internal curl shim, so we can use its (true)
|
/* We're using our internal curl shim, so we can use its (true)
|
||||||
SRV support. Obviously, CURLOPT_SRVTAG_GPG_HACK isn't a real
|
SRV support. Obviously, CURLOPT_SRVTAG_GPG_HACK isn't a real
|
||||||
libcurl option. It's specific to our shim. */
|
libcurl option. It's specific to our shim. */
|
||||||
@ -760,13 +853,6 @@ main(int argc,char *argv[])
|
|||||||
if(opt->auth)
|
if(opt->auth)
|
||||||
curl_easy_setopt(curl,CURLOPT_USERPWD,opt->auth);
|
curl_easy_setopt(curl,CURLOPT_USERPWD,opt->auth);
|
||||||
|
|
||||||
if(opt->debug)
|
|
||||||
{
|
|
||||||
fprintf(console,"gpgkeys: curl version = %s\n",curl_version());
|
|
||||||
curl_easy_setopt(curl,CURLOPT_STDERR,console);
|
|
||||||
curl_easy_setopt(curl,CURLOPT_VERBOSE,1L);
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,(long)opt->flags.check_cert);
|
curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,(long)opt->flags.check_cert);
|
||||||
curl_easy_setopt(curl,CURLOPT_CAINFO,opt->ca_cert_file);
|
curl_easy_setopt(curl,CURLOPT_CAINFO,opt->ca_cert_file);
|
||||||
|
|
||||||
@ -968,6 +1054,7 @@ main(int argc,char *argv[])
|
|||||||
free_ks_options(opt);
|
free_ks_options(opt);
|
||||||
|
|
||||||
curl_slist_free_all(headers);
|
curl_slist_free_all(headers);
|
||||||
|
curl_slist_free_all(resolve);
|
||||||
|
|
||||||
if(curl)
|
if(curl)
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
|
@ -66,6 +66,11 @@ AC_DEFUN([LIBCURL_CHECK_CONFIG],
|
|||||||
|
|
||||||
_libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'"
|
_libcurl_version_parse="eval $AWK '{split(\$NF,A,\".\"); X=256*256*A[[1]]+256*A[[2]]+A[[3]]; print X;}'"
|
||||||
|
|
||||||
|
# More recent versions of curl-config have a direct --vernum
|
||||||
|
# option, but we'd like this code to work with older versions as
|
||||||
|
# well, so just convert --version.
|
||||||
|
_libcurl_vernum_parse="eval $AWK '{printf \"0x%06X\",\$NF}'"
|
||||||
|
|
||||||
_libcurl_try_link=yes
|
_libcurl_try_link=yes
|
||||||
|
|
||||||
if test -d "$_libcurl_with" ; then
|
if test -d "$_libcurl_with" ; then
|
||||||
@ -206,6 +211,10 @@ x=CURLOPT_VERBOSE;
|
|||||||
AC_SUBST(LIBCURL_CPPFLAGS)
|
AC_SUBST(LIBCURL_CPPFLAGS)
|
||||||
AC_SUBST(LIBCURL)
|
AC_SUBST(LIBCURL)
|
||||||
|
|
||||||
|
_libcurl_vernum=`echo $_libcurl_version | $_libcurl_vernum_parse`
|
||||||
|
|
||||||
|
AC_DEFINE_UNQUOTED(LIBCURL_VERNUM,$_libcurl_vernum,[The version of the libcurl library in packed hex form])
|
||||||
|
|
||||||
for _libcurl_feature in $_libcurl_features ; do
|
for _libcurl_feature in $_libcurl_features ; do
|
||||||
AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1])
|
AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1])
|
||||||
eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes
|
eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes
|
||||||
@ -246,6 +255,7 @@ x=CURLOPT_VERBOSE;
|
|||||||
unset _libcurl_protocol
|
unset _libcurl_protocol
|
||||||
unset _libcurl_protocols
|
unset _libcurl_protocols
|
||||||
unset _libcurl_version
|
unset _libcurl_version
|
||||||
|
unset _libcurl_vernum
|
||||||
unset _libcurl_ldflags
|
unset _libcurl_ldflags
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user