From f2f12f41efe5a476833295dc6c44fcd887d0abe6 Mon Sep 17 00:00:00 2001 From: David Shaw Date: Tue, 18 Dec 2012 21:58:53 -0500 Subject: [PATCH] Fix issue 1446: honor ports given in SRV responses. * common/http.c (send_request, connect_server, http_open): Use a struct srv instead of a single srvtag so we can pass the chosen host and port back to the caller. (connect_server): Use the proper port in the HAVE_GETADDRINFO case. * keyserver/curl-shim.c (curl_easy_perform): Use struct srv and log chosen host and port. * keyserver/gpgkeys_hkp.c (main): Properly take the port given by SRV. Backported from ba9e974f1fd85b3dbbfb5e26d7a14f71d07c7cf2 --- include/http.h | 13 +++++++--- keyserver/curl-shim.c | 26 +++++++++++++++++--- keyserver/gpgkeys_hkp.c | 16 +++++++----- util/http.c | 54 +++++++++++++++++++++++------------------ 4 files changed, 74 insertions(+), 35 deletions(-) diff --git a/include/http.h b/include/http.h index 7959be837..1ecdc6062 100644 --- a/include/http.h +++ b/include/http.h @@ -1,6 +1,6 @@ /* http.h - HTTP protocol handler * Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, - * 2009 Free Software Foundation, Inc. + * 2009, 2012 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -73,14 +73,21 @@ struct http_context { }; typedef struct http_context *HTTP_HD; +struct http_srv +{ + const char *srvtag; + char *used_server; + unsigned short used_port; +}; + int http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url, char *auth, unsigned int flags, const char *proxy, - const char *srvtag, STRLIST headers ); + struct http_srv *srv, STRLIST headers ); void http_start_data( HTTP_HD hd ); int http_wait_response( HTTP_HD hd, unsigned int *ret_status ); void http_close( HTTP_HD hd ); int http_open_document( HTTP_HD hd, const char *document, char *auth, unsigned int flags, const char *proxy, - const char *srvtag, STRLIST headers ); + struct http_srv *srv, STRLIST headers ); #endif /*G10_HTTP_H*/ diff --git a/keyserver/curl-shim.c b/keyserver/curl-shim.c index 2df782638..857b5c184 100644 --- a/keyserver/curl-shim.c +++ b/keyserver/curl-shim.c @@ -1,7 +1,7 @@ /* curl-shim.c - Implement a small subset of the curl API in terms of * the iobuf HTTP API * - * Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. + * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2012 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -164,6 +164,9 @@ curl_easy_perform(CURL *curl) CURLcode err=CURLE_OK; const char *errstr=NULL; char *proxy=NULL; + struct http_srv srv; + + memset(&srv,0,sizeof(srv)); /* Emulate the libcurl proxy behavior. If the calling program set a proxy, use it. If it didn't set a proxy or set it to NULL, check @@ -176,10 +179,17 @@ curl_easy_perform(CURL *curl) else proxy=getenv(HTTP_PROXY_ENV); + if(curl->srvtag) + srv.srvtag=curl->srvtag; + if(curl->flags.verbose) { fprintf(curl->errors,"* HTTP proxy is \"%s\"\n",proxy?proxy:"null"); fprintf(curl->errors,"* HTTP URL is \"%s\"\n",curl->url); + if(srv.srvtag) + fprintf(curl->errors, + "* SRV tag is \"%s\": host and port may be overridden\n", + srv.srvtag); fprintf(curl->errors,"* HTTP auth is \"%s\"\n", curl->auth?curl->auth:"null"); fprintf(curl->errors,"* HTTP method is %s\n", @@ -189,12 +199,16 @@ curl_easy_perform(CURL *curl) if(curl->flags.post) { rc=http_open(&curl->hd,HTTP_REQ_POST,curl->url,curl->auth,0,proxy, - curl->srvtag,curl->headers?curl->headers->list:NULL); + &srv,curl->headers?curl->headers->list:NULL); if(rc==0) { char content_len[50]; unsigned int post_len=strlen(curl->postfields); + if(curl->flags.verbose && srv.used_server && srv.used_port) + fprintf (curl->errors, "* HTTP host:port post-SRV is \"%s:%hu\"\n", + srv.used_server, srv.used_port); + iobuf_writestr(curl->hd.fp_write, "Content-Type: application/x-www-form-urlencoded\r\n"); sprintf(content_len,"Content-Length: %u\r\n",post_len); @@ -211,9 +225,13 @@ curl_easy_perform(CURL *curl) else { rc=http_open(&curl->hd,HTTP_REQ_GET,curl->url,curl->auth,0,proxy, - curl->srvtag,curl->headers?curl->headers->list:NULL); + &srv,curl->headers?curl->headers->list:NULL); if(rc==0) { + if(curl->flags.verbose && srv.used_server && srv.used_port) + fprintf (curl->errors, "* HTTP host:port post-SRV is \"%s:%hu\"\n", + srv.used_server, srv.used_port); + rc=http_wait_response(&curl->hd,&curl->status); if(rc==0) { @@ -248,6 +266,8 @@ curl_easy_perform(CURL *curl) } } + free (srv.used_server); + switch(rc) { case 0: diff --git a/keyserver/gpgkeys_hkp.c b/keyserver/gpgkeys_hkp.c index b2e1a1a9a..27d67c6e6 100644 --- a/keyserver/gpgkeys_hkp.c +++ b/keyserver/gpgkeys_hkp.c @@ -1,6 +1,6 @@ /* gpgkeys_hkp.c - talk to an HKP keyserver * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, - * 2009 Free Software Foundation, Inc. + * 2009, 2012 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -690,6 +690,7 @@ main(int argc,char *argv[]) goto fail; } + /* Defaults */ if(ascii_strcasecmp(opt->scheme,"hkps")==0) { proto="https"; @@ -722,11 +723,9 @@ main(int argc,char *argv[]) goto fail; } - /* If the user gives a :port, then disable SRV. The semantics of a - specified port and SRV do not play well together. */ - if(opt->port) - port=opt->port; - else if(try_srv) + /* 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) { char *srvtag; @@ -751,6 +750,11 @@ main(int argc,char *argv[]) #endif } + /* If the user provided a port (or it came in via SRV, above), + replace the default. */ + if(opt->port) + port=opt->port; + curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errorbuffer); if(opt->auth) diff --git a/util/http.c b/util/http.c index 9aaa1d134..bab979613 100644 --- a/util/http.c +++ b/util/http.c @@ -1,6 +1,6 @@ /* http.c - HTTP protocol handler * Copyright (C) 1999, 2001, 2002, 2003, 2004, 2005, 2006, 2007, - * 2009 Free Software Foundation, Inc. + * 2009, 2012 Free Software Foundation, Inc. * * This file is part of GnuPG. * @@ -69,12 +69,12 @@ static int insert_escapes( byte *buffer, const byte *string, const byte *special ); static URI_TUPLE parse_tuple( byte *string ); static int send_request( HTTP_HD hd, const char *auth, const char *proxy, - const char *srvtag, STRLIST headers); + struct http_srv *srv, STRLIST headers); static byte *build_rel_path( PARSED_URI uri ); static int parse_response( HTTP_HD hd ); static int connect_server( const char *server, ushort port, unsigned int flags, - const char *srvtag ); + struct http_srv *srv ); static int write_server( int sock, const char *data, size_t length ); #ifdef _WIN32 @@ -150,7 +150,7 @@ make_radix64_string( const byte *data, size_t len ) int http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url, char *auth, unsigned int flags, const char *proxy, - const char *srvtag, STRLIST headers ) + struct http_srv *srv, STRLIST headers ) { int rc; @@ -166,7 +166,7 @@ http_open( HTTP_HD hd, HTTP_REQ_TYPE reqtype, const char *url, rc = parse_uri( &hd->uri, url ); if( !rc ) { - rc = send_request( hd, auth, proxy, srvtag, headers ); + rc = send_request( hd, auth, proxy, srv, headers ); if( !rc ) { hd->fp_write = iobuf_sockopen( hd->sock , "w" ); if( hd->fp_write ) @@ -234,12 +234,12 @@ http_wait_response( HTTP_HD hd, unsigned int *ret_status ) int http_open_document( HTTP_HD hd, const char *document, char *auth, - unsigned int flags, const char *proxy, const char *srvtag, + unsigned int flags, const char *proxy, struct http_srv *srv, STRLIST headers ) { int rc; - rc = http_open(hd, HTTP_REQ_GET, document, auth, flags, proxy, srvtag, + rc = http_open(hd, HTTP_REQ_GET, document, auth, flags, proxy, srv, headers ); if( rc ) return rc; @@ -523,7 +523,7 @@ parse_tuple( byte *string ) */ static int send_request( HTTP_HD hd, const char *auth, const char *proxy, - const char *srvtag, STRLIST headers ) + struct http_srv *srv, STRLIST headers ) { const byte *server; byte *request, *p; @@ -546,7 +546,7 @@ send_request( HTTP_HD hd, const char *auth, const char *proxy, return G10ERR_NETWORK; } hd->sock = connect_server( *uri->host? uri->host : "localhost", - uri->port? uri->port : 80, 0, NULL ); + uri->port? uri->port : 80, 0, srv ); if(uri->auth) { char *x; @@ -560,7 +560,7 @@ send_request( HTTP_HD hd, const char *auth, const char *proxy, release_parsed_uri( uri ); } else - hd->sock = connect_server( server, port, hd->flags, srvtag ); + hd->sock = connect_server( server, port, hd->flags, srv ); if(auth || hd->uri->auth) { @@ -815,9 +815,9 @@ start_server(void) static int connect_server( const char *server, ushort port, unsigned int flags, - const char *srvtag ) + struct http_srv *srv ) { - int sock=-1,srv,srvcount=0,connected=0,hostfound=0; + int sock=-1, srvindex, srvcount=0, connected=0, hostfound=0, chosen=-1; struct srventry *srvlist=NULL; #ifdef _WIN32 @@ -854,15 +854,15 @@ connect_server( const char *server, ushort port, unsigned int flags, #ifdef USE_DNS_SRV /* Do the SRV thing */ - if(srvtag) + if(srv && srv->srvtag) { /* We're using SRV, so append the tags */ - if(1+strlen(srvtag)+6+strlen(server)+1<=MAXDNAME) + if(1+strlen(srv->srvtag)+6+strlen(server)+1<=MAXDNAME) { char srvname[MAXDNAME]; strcpy(srvname,"_"); - strcat(srvname,srvtag); + strcat(srvname,srv->srvtag); strcat(srvname,"._tcp."); strcat(srvname,server); srvcount=getsrv(srvname,&srvlist); @@ -885,15 +885,15 @@ connect_server( const char *server, ushort port, unsigned int flags, #ifdef HAVE_GETADDRINFO - for(srv=0;srvai_addr,ai->ai_addrlen)==0) { connected=1; + chosen = srvindex; break; } @@ -924,7 +925,7 @@ connect_server( const char *server, ushort port, unsigned int flags, #else /* !HAVE_GETADDRINFO */ - for(srv=0;srvh_addrtype; if(addr.sin_family!=AF_INET) { - log_error("%s: unknown address family\n",srvlist[srv].target); + log_error("%s: unknown address family\n",srvlist[srvindex].target); return -1; } - addr.sin_port=htons(srvlist[srv].port); + addr.sin_port=htons(srvlist[srvindex].port); /* Try all A records until one responds. */ while(host->h_addr_list[i]) { if(host->h_length!=4) { - log_error("%s: illegal address length\n",srvlist[srv].target); + log_error("%s: illegal address length\n",srvlist[srvindex].target); return -1; } @@ -966,6 +967,7 @@ connect_server( const char *server, ushort port, unsigned int flags, if(connect(sock,(struct sockaddr *)&addr,sizeof(addr))==0) { connected=1; + chosen = srvindex; break; } @@ -979,6 +981,12 @@ connect_server( const char *server, ushort port, unsigned int flags, } #endif /* !HAVE_GETADDRINFO */ + if(chosen>-1 && srv) + { + srv->used_server = strdup (srvlist[chosen].target); + srv->used_port = srvlist[chosen].port; + } + free(srvlist); if(!connected)