From 3a2bfa183f686f371a7122f0752b77b1b2980300 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 24 Sep 2018 11:42:23 +0200 Subject: [PATCH 1/2] Fixed #4878: Added cidr support for proxy exception check. --- libfreerdp/core/proxy.c | 81 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 5 deletions(-) diff --git a/libfreerdp/core/proxy.c b/libfreerdp/core/proxy.c index f849010eb..0f8cbd7ae 100644 --- a/libfreerdp/core/proxy.c +++ b/libfreerdp/core/proxy.c @@ -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 = ","; @@ -154,16 +193,48 @@ static BOOL check_no_proxy(rdpSettings* settings, const char* no_proxy) { struct sockaddr_in sa4; struct sockaddr_in6 sa6; - BOOL is_ip = FALSE; + BOOL is_ipv4 = FALSE; + BOOL is_ipv6 = FALSE; if (inet_pton(AF_INET, settings->ServerHostname, &sa4.sin_addr) == 1) - is_ip = TRUE; + is_ipv4 = TRUE; else if (inet_pton(AF_INET6, settings->ServerHostname, &sa6.sin6_addr) == 1) - is_ip = TRUE; + is_ipv6 = TRUE; - if (is_ip) + if (is_ipv4 || is_ipv6) { - if (!strncmp(current, settings->ServerHostname, currentlen)) + char* rangedelim = strchr(current, '/'); + + /* 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)) + { + *rangedelim = '\0'; + + if (is_ipv4) + { + struct sockaddr_in mask; + + 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)) result = TRUE; /* left-aligned match for IPs */ } else if (current[0] == '.') /* Only compare if the no_proxy variable contains a whole domain. */ From 941213f50496523b1848f72fd3cbdf5a773b4722 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 24 Sep 2018 12:24:15 +0200 Subject: [PATCH 2/2] Fixed domain and regex match. --- libfreerdp/core/proxy.c | 116 +++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 61 deletions(-) diff --git a/libfreerdp/core/proxy.c b/libfreerdp/core/proxy.c index 0f8cbd7ae..66af0a716 100644 --- a/libfreerdp/core/proxy.c +++ b/libfreerdp/core/proxy.c @@ -149,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); @@ -175,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; } } @@ -185,71 +195,55 @@ 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_ipv4 = FALSE; - BOOL is_ipv6 = 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_ipv4 = TRUE; - else if (inet_pton(AF_INET6, settings->ServerHostname, &sa6.sin6_addr) == 1) - is_ipv6 = TRUE; - - if (is_ipv4 || is_ipv6) - { - char* rangedelim = strchr(current, '/'); - - /* 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)) - { - *rangedelim = '\0'; - - if (is_ipv4) - { - struct sockaddr_in mask; - - 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)) - 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) - { - const size_t offset = host_len - currentlen; - - if (!strncmp(current, settings->ServerHostname + offset, - currentlen)) - result = TRUE; /* right-aligned match for host names */ - } - } + 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, '/'); + + /* 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)) + { + *rangedelim = '\0'; + + if (is_ipv4) + { + struct sockaddr_in mask; + + 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 */ + } } current = strtok(NULL, delimiter);