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(atexit raise getpagesize strftime nl_langinfo setlocale)
|
||||
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_CHECK_TYPES([struct sigaction, sigset_t],,,[#include <signal.h>])
|
||||
|
@ -40,6 +40,20 @@
|
||||
#endif
|
||||
#ifdef HAVE_LIBCURL
|
||||
# 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
|
||||
# include "curl-shim.h"
|
||||
#endif
|
||||
@ -62,7 +76,8 @@ static char *proto,*port;
|
||||
static size_t
|
||||
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)
|
||||
{
|
||||
@ -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.
|
||||
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
|
||||
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;
|
||||
int srvcount, srvindex;
|
||||
char *portstr;
|
||||
|
||||
if(!srvtag)
|
||||
return;
|
||||
|
||||
portstr=malloc (MAX_PORT);
|
||||
if(!portstr)
|
||||
return;
|
||||
|
||||
if(1+strlen(srvtag)+6+strlen(opt->host)+1<=MAXDNAME)
|
||||
{
|
||||
char srvname[MAXDNAME];
|
||||
@ -516,30 +542,78 @@ srv_replace(const char *srvtag)
|
||||
strcat(srvname,srvtag);
|
||||
strcat(srvname,"._tcp.");
|
||||
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);
|
||||
newport=xtrymalloc(MAX_PORT);
|
||||
if(newname && newport)
|
||||
sprintf (portstr, "%hu", srvlist[srvindex].port);
|
||||
memset (&hints, 0, sizeof (hints));
|
||||
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);
|
||||
opt->host=newname;
|
||||
snprintf(newport,MAX_PORT,"%u",srvlist->port);
|
||||
opt->port=newport;
|
||||
opt->port=portstr;
|
||||
portstr=NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free (entry);
|
||||
free (host);
|
||||
}
|
||||
|
||||
freeaddrinfo (res);
|
||||
}
|
||||
else
|
||||
{
|
||||
free(newname);
|
||||
free(newport);
|
||||
continue; /* Not found */
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
free (srvlist);
|
||||
free (portstr);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -555,12 +629,20 @@ show_help (FILE *fp)
|
||||
int
|
||||
main(int argc,char *argv[])
|
||||
{
|
||||
int arg,ret=KEYSERVER_INTERNAL_ERROR,try_srv=1;
|
||||
int arg,ret=KEYSERVER_INTERNAL_ERROR;
|
||||
char line[MAX_LINE];
|
||||
int failed=0;
|
||||
struct keylist *keylist=NULL,*keyptr=NULL;
|
||||
char *proxy=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;
|
||||
|
||||
@ -723,6 +805,13 @@ main(int argc,char *argv[])
|
||||
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
|
||||
of a specified port and SRV do not play well together. */
|
||||
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
|
||||
possible targets at one particular level and work our way
|
||||
down the list, but it's better than nothing. */
|
||||
srv_replace(srvtag);
|
||||
#ifdef USE_DNS_SRV
|
||||
srv_replace(srvtag,&headers,&resolve);
|
||||
#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)
|
||||
SRV support. Obviously, CURLOPT_SRVTAG_GPG_HACK isn't a real
|
||||
libcurl option. It's specific to our shim. */
|
||||
@ -760,13 +853,6 @@ main(int argc,char *argv[])
|
||||
if(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_CAINFO,opt->ca_cert_file);
|
||||
|
||||
@ -968,6 +1054,7 @@ main(int argc,char *argv[])
|
||||
free_ks_options(opt);
|
||||
|
||||
curl_slist_free_all(headers);
|
||||
curl_slist_free_all(resolve);
|
||||
|
||||
if(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;}'"
|
||||
|
||||
# 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
|
||||
|
||||
if test -d "$_libcurl_with" ; then
|
||||
@ -206,6 +211,10 @@ x=CURLOPT_VERBOSE;
|
||||
AC_SUBST(LIBCURL_CPPFLAGS)
|
||||
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
|
||||
AC_DEFINE_UNQUOTED(AS_TR_CPP(libcurl_feature_$_libcurl_feature),[1])
|
||||
eval AS_TR_SH(libcurl_feature_$_libcurl_feature)=yes
|
||||
@ -246,6 +255,7 @@ x=CURLOPT_VERBOSE;
|
||||
unset _libcurl_protocol
|
||||
unset _libcurl_protocols
|
||||
unset _libcurl_version
|
||||
unset _libcurl_vernum
|
||||
unset _libcurl_ldflags
|
||||
fi
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user