Bug 459524 - Interpret SOCKS5 DNS reply more accurately, r=biesi
This commit is contained in:
Родитель
dc14a497a5
Коммит
848c75bbb8
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче