static PRStatus
nsSOCKSIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime to)
{
    PRStatus status;
    PRNetAddr dst;

    nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
    if (info == NULL) return PR_FAILURE;

    if (PR_NetAddrFamily(addr) == PR_AF_INET6 &&
        PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
        const uint8_t *srcp;

        LOGDEBUG(("socks: converting ipv4-mapped ipv6 address to ipv4"));

        // copied from _PR_ConvertToIpv4NetAddr()
        PR_InitializeNetAddr(PR_IpAddrAny, 0, &dst);
        srcp = addr->ipv6.ip.pr_s6_addr;
        memcpy(&dst.inet.ip, srcp + 12, 4);
        dst.inet.family = PR_AF_INET;
        dst.inet.port = addr->ipv6.port;
    } else {
        memcpy(&dst, addr, sizeof(dst));
    }

    info->SetDestinationAddr(&dst);
    info->SetConnectTimeout(to);

    do {
        status = info->DoHandshake(fd, -1);
    } while (status == PR_SUCCESS && !info->IsConnected());

    return status;
}
PRStatus
nsSOCKSSocketInfo::WriteV5ConnectRequest()
{
    // Send SOCKS 5 connect request
    PRNetAddr *addr = &mDestinationAddr;
    int32_t proxy_resolve;
    proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST;

    LOGDEBUG(("socks5: sending connection request (socks5 resolve? %s)",
             proxy_resolve? "yes" : "no"));

    mDataLength = 0;
    mState = SOCKS5_WRITE_CONNECT_REQUEST;

    WriteUint8(0x05); // version -- 5
    WriteUint8(0x01); // command -- connect
    WriteUint8(0x00); // reserved
   
    // Add the address to the SOCKS 5 request. SOCKS 5 supports several
    // address types, so we pick the one that works best for us.
    if (proxy_resolve) {
        // Add the host name. Only a single byte is used to store the length,
        // so we must prevent long names from being used.
        if (mDestinationHost.Length() > MAX_HOSTNAME_LEN) {
            LOGERROR(("socks5: destination host name is too long!"));
            HandshakeFinished(PR_BAD_ADDRESS_ERROR);
            return PR_FAILURE;
        }
        WriteUint8(0x03); // addr type -- domainname
        WriteUint8(mDestinationHost.Length()); // name length
        WriteString(mDestinationHost);
    } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
        WriteUint8(0x01); // addr type -- IPv4
        WriteNetAddr(addr);
    } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
        WriteUint8(0x04); // addr type -- IPv6
        WriteNetAddr(addr);
    } else {
        LOGERROR(("socks5: destination address of unknown type!"));
        HandshakeFinished(PR_BAD_ADDRESS_ERROR);
        return PR_FAILURE;
    }

    WriteNetPort(addr); // port

    return PR_SUCCESS;
}
PRStatus
nsSOCKSSocketInfo::WriteV4ConnectRequest()
{
    PRNetAddr *addr = &mDestinationAddr;
    int32_t proxy_resolve;

    NS_ABORT_IF_FALSE(mState == SOCKS_CONNECTING_TO_PROXY,
                      "Invalid state!");
    
    proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST;

    mDataLength = 0;
    mState = SOCKS4_WRITE_CONNECT_REQUEST;

    LOGDEBUG(("socks4: sending connection request (socks4a resolve? %s)",
             proxy_resolve? "yes" : "no"));

    // Send a SOCKS 4 connect request.
    WriteUint8(0x04); // version -- 4
    WriteUint8(0x01); // command -- connect
    WriteNetPort(addr);
    if (proxy_resolve) {
        // Add the full name, null-terminated, to the request
        // according to SOCKS 4a. A fake IP address, with the first
        // four bytes set to 0 and the last byte set to something other
        // than 0, is used to notify the proxy that this is a SOCKS 4a
        // request. This request type works for Tor and perhaps others.
        WriteUint32(PR_htonl(0x00000001)); // Fake IP
        WriteUint8(0x00); // Send an emtpy username
        if (mDestinationHost.Length() > MAX_HOSTNAME_LEN) {
            LOGERROR(("socks4: destination host name is too long!"));
            HandshakeFinished(PR_BAD_ADDRESS_ERROR);
            return PR_FAILURE;
        }
        WriteString(mDestinationHost); // Hostname
        WriteUint8(0x00);
    } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
        WriteNetAddr(addr); // Add the IPv4 address
        WriteUint8(0x00); // Send an emtpy username
    } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
        LOGERROR(("socks: SOCKS 4 can't handle IPv6 addresses!"));
        HandshakeFinished(PR_BAD_ADDRESS_ERROR);
        return PR_FAILURE;
    }

    return PR_SUCCESS;
}
PRStatus
nsSOCKSSocketInfo::ConnectToProxy(PRFileDesc *fd)
{
    PRStatus status;
    nsresult rv;

    NS_ABORT_IF_FALSE(mState == SOCKS_DNS_COMPLETE,
                      "Must have DNS to make connection!");

    if (NS_FAILED(mLookupStatus)) {
        PR_SetError(PR_BAD_ADDRESS_ERROR, 0);
        return PR_FAILURE;
    }

    // Try socks5 if the destination addrress is IPv6
    if (mVersion == 4 &&
        PR_NetAddrFamily(&mDestinationAddr) == PR_AF_INET6) {
        mVersion = 5;
    }

    int32_t addresses = 0;
    do {
        if (addresses++)
            mDnsRec->ReportUnusable(mProxyPort);
        
        rv = mDnsRec->GetNextAddr(mProxyPort, &mInternalProxyAddr);
        // No more addresses to try? If so, we'll need to bail
        if (NS_FAILED(rv)) {
            LOGERROR(("socks: unable to connect to SOCKS proxy, %s",
                     mProxyHost.get()));
            return PR_FAILURE;
        }

#if defined(PR_LOGGING)
        char buf[64];
        PR_NetAddrToString(&mInternalProxyAddr, buf, sizeof(buf));
        LOGDEBUG(("socks: trying proxy server, %s:%hu",
                 buf, PR_ntohs(PR_NetAddrInetPort(&mInternalProxyAddr))));
#endif
        PRNetAddr proxy = mInternalProxyAddr;
        FixupAddressFamily(fd, &proxy);
        status = fd->lower->methods->connect(fd->lower, &proxy, mTimeout);
        if (status != PR_SUCCESS) {
            PRErrorCode c = PR_GetError();
            // If EINPROGRESS, return now and check back later after polling
            if (c == PR_WOULD_BLOCK_ERROR || c == PR_IN_PROGRESS_ERROR) {
                mState = SOCKS_CONNECTING_TO_PROXY;
                return status;
            }
        }
    } while (status != PR_SUCCESS);

    // Connected now, start SOCKS
    if (mVersion == 4)
        return WriteV4ConnectRequest();
    return WriteV5AuthRequest();
}
void
nsSOCKSSocketInfo::WriteNetAddr(const PRNetAddr *addr)
{
    const char *ip = NULL;
    uint32_t len = 0;

    if (PR_NetAddrFamily(addr) == PR_AF_INET) {
        ip = (const char*)&addr->inet.ip;
        len = sizeof(addr->inet.ip);
    } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
        ip = (const char*)addr->ipv6.ip.pr_s6_addr;
        len = sizeof(addr->ipv6.ip.pr_s6_addr);
    }

    NS_ABORT_IF_FALSE(ip != NULL, "Unknown address");
    NS_ABORT_IF_FALSE(mDataLength + len <= BUFFER_SIZE,
                      "Can't write that much data!");
 
    memcpy(mData + mDataLength, ip, len);
    mDataLength += len;
}
void
nsSOCKSSocketInfo::FixupAddressFamily(PRFileDesc *fd, PRNetAddr *proxy)
{
    int32_t proxyFamily = PR_NetAddrFamily(&mInternalProxyAddr);
    // Do nothing if the address family is already matched
    if (proxyFamily == mDestinationFamily) {
        return;
    }
    // If the system does not support IPv6 and the proxy address is IPv6,
    // We can do nothing here.
    if (proxyFamily == PR_AF_INET6 && !ipv6Supported) {
        return;
    }
    // If the system does not support IPv6 and the destination address is
    // IPv6, convert IPv4 address to IPv4-mapped IPv6 address to satisfy
    // the emulation layer
    if (mDestinationFamily == PR_AF_INET6 && !ipv6Supported) {
        proxy->ipv6.family = PR_AF_INET6;
        proxy->ipv6.port = mInternalProxyAddr.inet.port;
        uint8_t *proxyp = proxy->ipv6.ip.pr_s6_addr;
        memset(proxyp, 0, 10);
        memset(proxyp + 10, 0xff, 2);
        memcpy(proxyp + 12,(char *) &mInternalProxyAddr.inet.ip, 4);
        // mDestinationFamily should not be updated
        return;
    }
    // Get an OS native handle from a specified FileDesc
    PROsfd osfd = PR_FileDesc2NativeHandle(fd);
    if (osfd == -1) {
        return;
    }
    // Create a new FileDesc with a specified family
    PRFileDesc *tmpfd = PR_OpenTCPSocket(proxyFamily);
    if (!tmpfd) {
        return;
    }
    PROsfd newsd = PR_FileDesc2NativeHandle(tmpfd);
    if (newsd == -1) {
        PR_Close(tmpfd);
        return;
    }
    // Must succeed because PR_FileDesc2NativeHandle succeeded
    fd = PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER);
    MOZ_ASSERT(fd);
    // Swap OS native handles
    PR_ChangeFileDescNativeHandle(fd, newsd);
    PR_ChangeFileDescNativeHandle(tmpfd, osfd);
    // Close temporary FileDesc which is now associated with
    // old OS native handle
    PR_Close(tmpfd);
    mDestinationFamily = proxyFamily;
}
Beispiel #7
0
TPS_PUBLIC PSHttpResponse *HttpConnection::getResponse(int index, const char *servlet, const char *body) {
    char *host_port;
    char uri[800];
    char *nickname;
    const char *httpprotocol;

    ConnectionInfo *failoverList = GetFailoverList();
    int len = failoverList->ConnectionInfo::GetHostPortListLen(); 
    if (index >= len) {
      index = len - 1; // use the last one
    }
    host_port= (failoverList->GetHostPortList())[index];

    if (IsSSL()) {
        httpprotocol = "https";
    } else {
        httpprotocol = "http";
    }

    PR_snprintf((char *)uri, 800,
      "%s://%s/%s",
      httpprotocol, host_port, servlet);

    RA::Debug("HttpConnection::getResponse", "Send request to host %s servlet %s", host_port, servlet);

    RA::Debug(LL_PER_PDU, "HttpConnection::getResponse", "uri=%s", uri);
    RA::Debug(LL_PER_PDU, "HttpConnection::getResponse", "host_port=%s", host_port);

    char *pPort = NULL;
    char *pPortActual = NULL;


    char hostName[512];

    /*
     * Isolate the host name, account for IPV6 numeric addresses.
     *
     */

    if(host_port)
        strncpy(hostName,host_port,512);

    pPort = hostName;
    while(1)  {
        pPort = strchr(pPort, ':');
        if (pPort) {
            pPortActual = pPort;
            pPort++;
        } else
            break;
    }

    if(pPortActual)
        *pPortActual = '\0';


    /*
    *  Rifle through the values for the host
    */

    PRAddrInfo *ai;
    void *iter;
    PRNetAddr addr;
    int family = PR_AF_INET;

    ai = PR_GetAddrInfoByName(hostName, PR_AF_UNSPEC, PR_AI_ADDRCONFIG);
    if (ai) {
        printf("%s\n", PR_GetCanonNameFromAddrInfo(ai));
        iter = NULL;
        while ((iter = PR_EnumerateAddrInfo(iter, ai, 0, &addr)) != NULL) {
            char buf[512];
            PR_NetAddrToString(&addr, buf, sizeof buf);
            RA::Debug( LL_PER_PDU,
                       "HttpConnection::getResponse: ",
                           "Sending addr -- Msg='%s'\n",
                           buf );
            family = PR_NetAddrFamily(&addr);
            RA::Debug( LL_PER_PDU,
                       "HttpConnection::getResponse: ",
                           "Sending family -- Msg='%d'\n",
                           family );
            break;
        }
        PR_FreeAddrInfo(ai);
        
    }

    PSHttpServer httpserver(host_port, family);
    nickname = GetClientNickname();
    if (IsSSL())
       httpserver.setSSL(PR_TRUE);
    else
       httpserver.setSSL(PR_FALSE);

    PSHttpRequest httprequest(&httpserver, uri, HTTP11, 0);
    if (IsSSL()) {
        httprequest.setSSL(PR_TRUE);
        if (nickname != NULL) {
            httprequest.setCertNickName(nickname);
        } else {
            return NULL;
        }
    } else
        httprequest.setSSL(PR_FALSE);

    httprequest.setMethod("POST");

    if (body != NULL) {
        httprequest.setBody( strlen(body), body);
    }

    httprequest.addHeader( "Content-Type", "application/x-www-form-urlencoded" );
    if (m_headers != NULL) {
        for (int i=0; i<m_headers->Size(); i++) {
            char *name = m_headers->GetNameAt(i);
            httprequest.addHeader(name, m_headers->GetValue(name));
        }
    }

    if (IsKeepAlive())
        httprequest.addHeader( "Connection", "keep-alive" );

    HttpEngine httpEngine;
    return httpEngine.makeRequest(httprequest, httpserver, (PRIntervalTime)GetTimeout(),
      PR_FALSE /*expectChunked*/);
}
/** Create socket and connect to it.
  @param hostname Hostname to connect
  @param port Port name/number to connect
  @param mode Connection mode. Bit-array of MODE_NO_SSL, MODE_IP6MODE, MODE_IP4MODE.
  @return NULL on error, otherwise connected socket.
*/
static PRFileDesc *create_connected_socket(char *hostname,int port,int mode) {
  PRAddrInfo *addr_info;
  void *addr_iter;
  PRNetAddr addr;
  PRFileDesc *localsocket;
  int can_exit,valid_socket;
  PRUint16 af_spec;

  localsocket=NULL;

  addr_info=NULL;

  af_spec=PR_AF_UNSPEC;

  if (!(mode&MODE_IP6MODE)) af_spec=PR_AF_INET;

  addr_info=PR_GetAddrInfoByName(hostname,af_spec,PR_AI_ADDRCONFIG);

  if (addr_info == NULL) {
    print_nspr_error();
    return NULL;
  }

  /*We have socket -> enumerate and try to connect*/
  addr_iter=NULL;
  can_exit=0;
  valid_socket=0;

  while (!can_exit) {
    addr_iter=PR_EnumerateAddrInfo(addr_iter,addr_info,port,&addr);

    if (addr_iter==NULL) {
      can_exit=1;
    } else {
      if ((PR_NetAddrFamily(&addr)==PR_AF_INET && (mode&MODE_IP4MODE)) ||
          (PR_NetAddrFamily(&addr)==PR_AF_INET6 && (mode&MODE_IP6MODE))) {
        /*Type of address is what user want, try to create socket and make connection*/

        /*Create socket*/
        localsocket=create_socket(!(mode&MODE_NO_SSL),(PR_NetAddrFamily(&addr)==PR_AF_INET6));

        if (localsocket) {
          /*Try to connect*/
          if (PR_Connect(localsocket,&addr,PR_INTERVAL_NO_TIMEOUT)==PR_SUCCESS) {
            /*Force handshake*/
            if ((!(mode&MODE_NO_SSL)) && SSL_ForceHandshake(localsocket)!=SECSuccess) {
              /*Handhake failure -> fail*/
              print_nspr_error();
              if (PR_Close(localsocket)!=PR_SUCCESS) {
                print_nspr_error();
                can_exit=1;
              }
              localsocket=NULL;
            }

            /*Socket is connected -> we can return it*/
            can_exit=1;
          } else {
            /*Try another address*/
            if (PR_Close(localsocket)!=PR_SUCCESS) {
              print_nspr_error();
              can_exit=1;
            }
            localsocket=NULL;
          }
        }
      }
    }
  }

  if (!localsocket) {
    /*Socket is unvalid -> we don't found any usable address*/
    fprintf(stderr,"Can't connect to host %s on port %d!\n",hostname,port);
  }

  PR_FreeAddrInfo(addr_info);

  return localsocket;
}