Merge pull request #4882 from akallabeth/no_proxy_cidr

Fixed #4878: Added cidr support for proxy exception check.
This commit is contained in:
Martin Fleisz 2018-09-26 09:20:54 +02:00 committed by GitHub
commit 5339efd6e4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 88 additions and 23 deletions

View File

@ -103,6 +103,45 @@ BOOL proxy_prepare(rdpSettings* settings, const char** lpPeerHostname, UINT16* l
return FALSE;
}
static BOOL cidr4_match(const struct in_addr* addr, const struct in_addr* net, BYTE bits)
{
uint32_t mask, amask, nmask;
if (bits == 0)
return TRUE;
mask = htonl(0xFFFFFFFFu << (32 - bits));
amask = addr->s_addr & mask;
nmask = net->s_addr & mask;
return amask == nmask;
}
static BOOL cidr6_match(const struct in6_addr* address, const struct in6_addr* network,
uint8_t bits)
{
const uint32_t* a = (const uint32_t*)address;
const uint32_t* n = (const uint32_t*)network;
size_t bits_whole, bits_incomplete;
bits_whole = bits >> 5;
bits_incomplete = bits & 0x1F;
if (bits_whole)
{
if (memcmp(a, n, bits_whole << 2) != 0)
return FALSE;
}
if (bits_incomplete)
{
uint32_t mask = htonl((0xFFFFFFFFu) << (32 - bits_incomplete));
if ((a[bits_whole] ^ n[bits_whole]) & mask)
return FALSE;
}
return TRUE;
}
static BOOL check_no_proxy(rdpSettings* settings, const char* no_proxy)
{
const char* delimiter = ",";
@ -110,10 +149,19 @@ static BOOL check_no_proxy(rdpSettings* settings, const char* no_proxy)
char* current;
char* copy;
size_t host_len;
struct sockaddr_in sa4;
struct sockaddr_in6 sa6;
BOOL is_ipv4 = FALSE;
BOOL is_ipv6 = FALSE;
if (!no_proxy || !settings)
return FALSE;
if (inet_pton(AF_INET, settings->ServerHostname, &sa4.sin_addr) == 1)
is_ipv4 = TRUE;
else if (inet_pton(AF_INET6, settings->ServerHostname, &sa6.sin6_addr) == 1)
is_ipv6 = TRUE;
host_len = strlen(settings->ServerHostname);
copy = _strdup(no_proxy);
@ -136,8 +184,9 @@ static BOOL check_no_proxy(rdpSettings* settings, const char* no_proxy)
if (host_len >= currentlen)
{
const size_t offset = host_len + 1 - currentlen;
const char* name = settings->ServerHostname + offset;
if (strncmp(current + 1, settings->ServerHostname + offset, currentlen - 1) == 0)
if (strncmp(current + 1, name, currentlen - 1) == 0)
result = TRUE;
}
}
@ -146,38 +195,54 @@ static BOOL check_no_proxy(rdpSettings* settings, const char* no_proxy)
if (strncmp(current, settings->ServerHostname, currentlen - 1) == 0)
result = TRUE;
}
else
else if (current[0] == '.') /* Only compare if the no_proxy variable contains a whole domain. */
{
if (strcmp(current, settings->ServerHostname) == 0)
result = TRUE; /* exact match */
else
if (host_len > currentlen)
{
struct sockaddr_in sa4;
struct sockaddr_in6 sa6;
BOOL is_ip = FALSE;
const size_t offset = host_len - currentlen;
const char* name = settings->ServerHostname + offset;
if (inet_pton(AF_INET, settings->ServerHostname, &sa4.sin_addr) == 1)
is_ip = TRUE;
else if (inet_pton(AF_INET6, settings->ServerHostname, &sa6.sin6_addr) == 1)
is_ip = TRUE;
if (strncmp(current, name, currentlen) == 0)
result = TRUE; /* right-aligned match for host names */
}
}
else if (strcmp(current, settings->ServerHostname) == 0)
result = TRUE; /* exact match */
else if (is_ipv4 || is_ipv6)
{
char* rangedelim = strchr(current, '/');
if (is_ip)
/* Check for IP ranges */
if (rangedelim != NULL)
{
const char* range = rangedelim + 1;
int sub;
int rc = sscanf(range, "%u", &sub);
if ((rc == 1) && (rc >= 0))
{
if (!strncmp(current, settings->ServerHostname, currentlen))
result = TRUE; /* left-aligned match for IPs */
}
else if (current[0] == '.') /* Only compare if the no_proxy variable contains a whole domain. */
{
if (host_len >= currentlen)
*rangedelim = '\0';
if (is_ipv4)
{
const size_t offset = host_len - currentlen;
struct sockaddr_in mask;
if (!strncmp(current, settings->ServerHostname + offset,
currentlen))
result = TRUE; /* right-aligned match for host names */
if (inet_pton(AF_INET, current, &mask.sin_addr))
result = cidr4_match(&sa4.sin_addr, &mask.sin_addr, sub);
}
else if (is_ipv6)
{
struct sockaddr_in6 mask;
if (inet_pton(AF_INET6, current, &mask.sin6_addr))
result = cidr6_match(&sa6.sin6_addr, &mask.sin6_addr, sub);
}
}
else
WLog_WARN(TAG, "NO_PROXY invalid entry %s", current);
}
else if (strncmp(current, settings->ServerHostname, currentlen) == 0)
result = TRUE; /* left-aligned match for IPs */
}
}