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; }
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; }