request_len = 6;
request_len = 0;
ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRIntervalTime timeout){    NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED);    NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED);    NS_ENSURE_TRUE(extAddr, NS_ERROR_NOT_INITIALIZED);    unsigned char request[22];    int request_len = 0;    unsigned char response[22];    int response_len = 0;    request[0] = 0x05; // SOCKS version 5    request[1] = 0x01; // number of auth procotols we recognize    // auth protocols    request[2] = 0x00; // no authentication required    // compliant implementations MUST implement GSSAPI    // and SHOULD implement username/password and MAY    // implement CHAP    // TODO: we don't implement these    //request[3] = 0x01; // GSSAPI    //request[4] = 0x02; // username/password    //request[5] = 0x03; // CHAP    request_len = 2 + request[1];    int write_len = PR_Send(fd, request, request_len, 0, timeout);    if (write_len != request_len) {        LOGERROR(("PR_Send() failed. Wrote: %d bytes; Expected: %d.", write_len, request_len));        return NS_ERROR_FAILURE;    }        // get the server's response. Use PR_Recv() instead of     response_len = 2;    response_len = PR_Recv(fd, response, response_len, 0, timeout);        if (response_len <= 0) {        LOGERROR(("PR_Recv() failed. response_len = %d.", response_len));        return NS_ERROR_FAILURE;    }        if (response[0] != 0x05) {        // it's a either not SOCKS or not our version        LOGERROR(("Not a SOCKS 5 reply. Expected: 5; received: %x", response[0]));        return NS_ERROR_FAILURE;    }    switch (response[1]) {        case 0x00:            // no auth            break;        case 0x01:            // GSSAPI            // TODO: implement            LOGERROR(("Server want to use GSSAPI to authenticate, but we don't support it."));            return NS_ERROR_FAILURE;        case 0x02:            // username/password            // TODO: implement            LOGERROR(("Server want to use username/password to authenticate, but we don't support it."));            return NS_ERROR_FAILURE;        case 0x03:            // CHAP            // TODO: implement?            LOGERROR(("Server want to use CHAP to authenticate, but we don't support it."));            return NS_ERROR_FAILURE;        default:            // unrecognized auth method            LOGERROR(("Uncrecognized authentication method received: %x", response[1]));            return NS_ERROR_FAILURE;    }        // we are now authenticated, so lets tell    // the server where to connect to        request_len = 6;        request[0] = 0x05; // SOCKS version 5    request[1] = 0x01; // CONNECT command    request[2] = 0x00; // obligatory reserved field (perfect for MS tampering!)        if (PR_NetAddrFamily(addr) == PR_AF_INET) {                request[3] = 0x01; // encoding of destination address (1 == IPv4)        request_len += 4;                char * ip = (char*)(&addr->inet.ip);        request[4] = *ip++;        request[5] = *ip++;        request[6] = *ip++;        request[7] = *ip++;            } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {                request[3] = 0x04; // encoding of destination address (4 == IPv6)        request_len += 16;                char * ip = (char*)(&addr->ipv6.ip.pr_s6_addr);        request[4] = *ip++; request[5] = *ip++; request[6] = *ip++; request[7] = *ip++;        request[8] = *ip++; request[9] = *ip++; request[10] = *ip++; request[11] = *ip++;        request[12] = *ip++; request[13] = *ip++; request[14] = *ip++; request[15] = *ip++;        request[16] = *ip++; request[17] = *ip++; request[18] = *ip++; request[19] = *ip++;                // we're going to test to see if this address can        // be mapped back into IPv4 without loss. if so,        // we'll use IPv4 instead, as reliable SOCKS server         // support for IPv6 is probably questionable.                if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {                        request[3] = 0x01; // ipv4 encoding            request[4] = request[16];            request[5] = request[17];            request[6] = request[18];            request[7] = request[19];            request_len -= 12;                    }            } else {                // Unknown address type        LOGERROR(("Don't know what kind of IP address this is."));        return NS_ERROR_FAILURE;    }        // destination port    PRUint16 destPort = PR_htons(PR_NetAddrInetPort(addr));        request[request_len-2] = (unsigned char)(destPort >> 8);    request[request_len-1] = (unsigned char)destPort;        write_len = PR_Send(fd, request, request_len, 0, timeout);    if (write_len != request_len) {        // bad write        LOGERROR(("PR_Send() failed sending connect command. Wrote: %d bytes; Expected: %d.", write_len, request_len));        return NS_ERROR_FAILURE;    }        response_len = 22;    response_len = PR_Recv(fd, response, response_len, 0, timeout);    if (response_len <= 0) {        // bad read        LOGERROR(("PR_Recv() failed getting connect command reply. response_len = %d.", response_len));        return NS_ERROR_FAILURE;    }        if (response[0] != 0x05) {        // bad response        LOGERROR(("Not a SOCKS 5 reply. Expected: 5; received: %x", response[0]));        return NS_ERROR_FAILURE;    }        switch(response[1]) {        case 0x00:  break;      // success        case 0x01:  LOGERROR(("SOCKS 5 server rejected connect request: 01, General SOCKS server failure."));                    return NS_ERROR_FAILURE;        case 0x02:  LOGERROR(("SOCKS 5 server rejected connect request: 02, Connection not allowed by ruleset."));                    return NS_ERROR_FAILURE;        case 0x03:  LOGERROR(("SOCKS 5 server rejected connect request: 03, Network unreachable."));                    return NS_ERROR_FAILURE;        case 0x04:  LOGERROR(("SOCKS 5 server rejected connect request: 04, Host unreachable."));                    return NS_ERROR_FAILURE;        case 0x05:  LOGERROR(("SOCKS 5 server rejected connect request: 05, Connection refused."));                    return NS_ERROR_FAILURE;        case 0x06:  LOGERROR(("SOCKS 5 server rejected connect request: 06, TTL expired."));                    return NS_ERROR_FAILURE;        case 0x07:  LOGERROR(("SOCKS 5 server rejected connect request: 07, Command not supported."));                    return NS_ERROR_FAILURE;        case 0x08:  LOGERROR(("SOCKS 5 server rejected connect request: 08, Address type not supported."));                    return NS_ERROR_FAILURE;        default:    LOGERROR(("SOCKS 5 server rejected connect request: %x.", response[1]));                    return NS_ERROR_FAILURE;            }            // get external bound address (this is what     // the outside world sees as "us")    char *ip = nsnull;    PRUint16 extPort = 0;    switch (response[3]) {        case 0x01: // IPv4                        extPort = (response[8] << 8) | response[9];                        PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET, extPort, extAddr);                        ip = (char*)(&extAddr->inet.ip);            *ip++ = response[4];            *ip++ = response[5];            *ip++ = response[6];            *ip++ = response[7];                        break;        case 0x04: // IPv6                        extPort = (response[20] << 8) | response[21];                        PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, extPort, extAddr);                        ip = (char*)(&extAddr->ipv6.ip.pr_s6_addr);            *ip++ = response[4]; *ip++ = response[5]; *ip++ = response[6]; *ip++ = response[7];            *ip++ = response[8]; *ip++ = response[9]; *ip++ = response[10]; *ip++ = response[11];            *ip++ = response[12]; *ip++ = response[13]; *ip++ = response[14]; *ip++ = response[15];            *ip++ = response[16]; *ip++ = response[17]; *ip++ = response[18]; *ip++ = response[19];                        break;        case 0x03: // FQDN (should not get this back)        default: // unknown format            // if we get here, we don't know our external address.            // however, as that's possibly not critical to the user,            // we let it slide.            PR_InitializeNetAddr(PR_IpAddrNull, 0, extAddr);            //return NS_ERROR_FAILURE;            break;    }    return NS_OK;}