Index: src/cgi.c ================================================================== --- src/cgi.c +++ src/cgi.c @@ -42,10 +42,11 @@ #endif #include <time.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> +#include <netdb.h> #include "cgi.h" #if INTERFACE /* ** Shortcuts for cgi_parameter. P("x") returns the value of query parameter @@ -1119,10 +1120,21 @@ } if( zLeftOver ){ *zLeftOver = zInput; } return zResult; } +/* +** All possible forms of an IP address. Needed to work around GCC strict +** aliasing rules. +*/ +typedef union { + struct sockaddr sa; /* Abstract superclass */ + struct sockaddr_in sa4; /* IPv4 */ + struct sockaddr_in6 sa6; /* IPv6 */ + struct sockaddr_storage sas; /* Should be the maximum of the above 3 */ +} address; + /* ** This routine handles a single HTTP request which is coming in on ** standard input and which replies on standard output. ** ** The HTTP request is read from standard input and is used to initialize @@ -1157,15 +1169,19 @@ cgi_setenv("REQUEST_URI", zToken); for(i=0; zToken[i] && zToken[i]!='?'; i++){} if( zToken[i] ) zToken[i++] = 0; cgi_setenv("PATH_INFO", zToken); cgi_setenv("QUERY_STRING", &zToken[i]); - if( zIpAddr==0 && - getpeername(fileno(g.httpIn), (struct sockaddr*)&remoteName, - &size)>=0 - ){ - zIpAddr = inet_ntoa(remoteName.sin_addr); + if( zIpAddr==0 ){ + address remoteAddr; + unsigned int size = sizeof(remoteAddr); + char zHost[NI_MAXHOST]; + if( getpeername(fileno(g.httpIn), &remoteAddr.sa, &size)>=0 ){ + getnameinfo(&remoteAddr.sa, size, zHost, sizeof(zHost), 0, 0, + NI_NUMERICHOST); + zIpAddr = mprintf("%s", zHost); + } } if( zIpAddr ){ cgi_setenv("REMOTE_ADDR", zIpAddr); g.zIpAddr = mprintf("%s", zIpAddr); } Index: src/http_socket.c ================================================================== --- src/http_socket.c +++ src/http_socket.c @@ -41,10 +41,11 @@ # include <netdb.h> #endif #include <assert.h> #include <sys/types.h> #include <signal.h> +#include <errno.h> /* ** There can only be a single socket connection open at a time. ** State information about that socket is stored in the following ** local variables: @@ -136,46 +137,61 @@ ** ** Return the number of errors. */ int socket_open(void){ static struct sockaddr_in addr; /* The server address */ - static int addrIsInit = 0; /* True once addr is initialized */ + static int addrIsInit = 0; /* True when initialized once */ + static struct addrinfo *p = 0; /* Succcessful open */ socket_global_init(); if( !addrIsInit ){ - addr.sin_family = AF_INET; - addr.sin_port = htons(g.urlPort); - *(int*)&addr.sin_addr = inet_addr(g.urlName); - if( -1 == *(int*)&addr.sin_addr ){ -#ifndef FOSSIL_STATIC_LINK - struct hostent *pHost; - pHost = gethostbyname(g.urlName); - if( pHost!=0 ){ - memcpy(&addr.sin_addr,pHost->h_addr_list[0],pHost->h_length); - }else -#endif - { - socket_set_errmsg("can't resolve host name: %s", g.urlName); - return 1; - } + struct addrinfo sHints; + int rc; + char zPort[30]; + + memset(&sHints, 0, sizeof(sHints)); + sHints.ai_family = AF_UNSPEC; + sHints.ai_socktype = SOCK_STREAM; + sHints.ai_flags = 0; + sHints.ai_protocol = 0; + sqlite3_snprintf(sizeof(zPort), zPort, "%d", g.urlPort); + rc = getaddrinfo(g.urlName, zPort, &sHints, &p); + if( rc!=0 ){ + fossil_fatal("getaddrinfo(\"%s\",\"%s\",...): %s", + g.urlName, zPort, gai_strerror(rc)); + } + if( p==0 ){ + fossil_fatal("no IP addresses returned by getaddrinfo()"); } addrIsInit = 1; + } - /* Set the Global.zIpAddr variable to the server we are talking to. - ** This is used to populate the ipaddr column of the rcvfrom table, - ** if any files are received from the server. - */ - g.zIpAddr = mprintf("%s", inet_ntoa(addr.sin_addr)); - } - iSocket = socket(AF_INET,SOCK_STREAM,0); - if( iSocket<0 ){ - socket_set_errmsg("cannot create a socket"); - return 1; + while( p ){ + char zHost[NI_MAXHOST]; + iSocket = socket(p->ai_family, p->ai_socktype, p->ai_protocol); + if( iSocket<0 ){ + fossil_warning("socket() failed: %s", strerror(errno)); + p = p->ai_next; + continue; + } + if( connect(iSocket, p->ai_addr, p->ai_addrlen)<0 ){ + fossil_warning("connect() failed: %s", strerror(errno)); + p = p->ai_next; + socket_close(); + continue; + } + p->ai_next = 0; + if( getnameinfo(p->ai_addr, p->ai_addrlen, zHost, sizeof(zHost), + 0, 0, NI_NUMERICHOST)==0 ){ + g.zIpAddr = mprintf("%s", zHost); + }else{ + fossil_fatal("cannot find numeric host IP address"); + } + break; } - if( connect(iSocket,(struct sockaddr*)&addr,sizeof(addr))<0 ){ - socket_set_errmsg("cannot connect to host %s:%d", g.urlName, g.urlPort); - socket_close(); + if( p==0 ){ + socket_set_errmsg("cannot create a socket"); return 1; } #if !defined(_WIN32) signal(SIGPIPE, SIG_IGN); #endif Index: src/url.c ================================================================== --- src/url.c +++ src/url.c @@ -101,12 +101,22 @@ } for(j=i+1; (c=zUrl[j])!=0 && c!='/' && c!=':'; j++){} g.urlName = mprintf("%.*s", j-i-1, &zUrl[i+1]); i = j; }else{ - for(i=iStart; (c=zUrl[i])!=0 && c!='/' && c!=':'; i++){} + int inSquare = 0; + int n; + for(i=iStart; (c=zUrl[i])!=0 && c!='/' && (inSquare || c!=':'); i++){ + if( c=='[' ) inSquare = 1; + if( c==']' ) inSquare = 0; + } g.urlName = mprintf("%.*s", i-iStart, &zUrl[iStart]); + n = strlen(g.urlName); + if( g.urlName[0]=='[' && n>2 && g.urlName[n-1]==']' ){ + g.urlName++; + g.urlName[n-2] = 0; + } zLogin = mprintf(""); } url_tolower(g.urlName); if( c==':' ){ g.urlPort = 0;