Bug 459524 - Interpret SOCKS5 DNS reply more accurately, r=biesi

This commit is contained in:
Nelson Bolyard 2009-03-10 16:14:06 -04:00
Родитель dc14a497a5
Коммит 848c75bbb8
1 изменённых файлов: 65 добавлений и 29 удалений

Просмотреть файл

@ -162,21 +162,41 @@ nsSOCKSSocketInfo::SetInternalProxyAddr(PRNetAddr *aInternalProxyAddr)
return NS_OK;
}
static PRInt32
pr_RecvAll(PRFileDesc *fd, unsigned char *buf, PRInt32 amount, PRIntn flags,
PRIntervalTime timeout)
{
PRInt32 bytesRead = 0;
PRInt32 offset = 0;
while (offset < amount) {
bytesRead = PR_Recv(fd, buf + offset, amount - offset, flags, timeout);
if (bytesRead > 0) {
offset += bytesRead;
} else if (bytesRead == 0 || offset != 0) {
return offset;
} else {
return bytesRead;
}
}
return offset;
}
// Negotiate a SOCKS 5 connection. Assumes the TCP connection to the socks
// server port has been established.
static nsresult
ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRIntervalTime timeout)
{
int request_len = 0;
int response_len = 0;
int desired_len = 0;
unsigned char request[22];
unsigned char response[262];
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
@ -197,11 +217,11 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter
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);
// get the server's response.
desired_len = 2;
response_len = pr_RecvAll(fd, response, desired_len, 0, timeout);
if (response_len <= 0) {
if (response_len < desired_len) {
LOGERROR(("PR_Recv() failed. response_len = %d.", response_len));
return NS_ERROR_FAILURE;
@ -357,17 +377,14 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter
return NS_ERROR_FAILURE;
}
response_len = 22;
response_len = PR_Recv(fd, response, response_len, 0, timeout);
if (response_len <= 0) {
// bad read
desired_len = 5;
response_len = pr_RecvAll(fd, response, desired_len, 0, timeout);
if (response_len < desired_len) { // 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;
@ -397,6 +414,26 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter
}
switch (response[3]) {
case 0x01: // IPv4
desired_len = 4 + 2 - 1;
break;
case 0x03: // FQDN
desired_len = response[4] + 2;
break;
case 0x04: // IPv6
desired_len = 16 + 2 - 1;
break;
default: // unknown format
return NS_ERROR_FAILURE;
break;
}
response_len = pr_RecvAll(fd, response + 5, desired_len, 0, timeout);
if (response_len < desired_len) { // bad read
LOGERROR(("PR_Recv() failed getting connect command reply. response_len = %d.", response_len));
return NS_ERROR_FAILURE;
}
response_len += 5;
// get external bound address (this is what
// the outside world sees as "us")
@ -434,17 +471,16 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter
*ip++ = response[18]; *ip++ = response[19];
break;
case 0x03: // FQDN (should not get this back)
default: // unknown format
case 0x03: // FQDN
// 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;
extPort = (response[response_len - 2] << 8) |
response[response_len - 1];
PR_InitializeNetAddr(PR_IpAddrNull, extPort, extAddr);
break;
}
return NS_OK;
}
// Negotiate a SOCKS 4 connection. Assumes the TCP connection to the socks
@ -452,15 +488,16 @@ ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRInter
static nsresult
ConnectSOCKS4(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
{
NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED);
unsigned char request[12];
int request_len = 0;
int write_len;
unsigned char response[10];
int response_len = 0;
int desired_len = 0;
char *ip = nsnull;
unsigned char request[12];
unsigned char response[10];
NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED);
NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED);
request[0] = 0x04; // SOCKS version 4
request[1] = 0x01; // CD command code -- 1 for connect
@ -564,10 +601,9 @@ ConnectSOCKS4(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
}
// get the server's response
response_len = 8; // size of the response
response_len = PR_Recv(fd, response, response_len, 0, timeout);
if (response_len <= 0) {
desired_len = 8; // size of the response
response_len = pr_RecvAll(fd, response, desired_len, 0, timeout);
if (response_len < desired_len) {
LOGERROR(("PR_Recv() failed. response_len = %d.", response_len));
return NS_ERROR_FAILURE;
}