/** * @brief Checks if a buffer points to a valid short IPv6 range-expressed * network. "::200:ff:1-fee5" is valid. * * @param str String to check in. * * @return 1 if str points to a valid short-range IPv6 network, 0 otherwise. */ static int is_short_range6_network (const char *str) { char *ip_str, *end_str, *p; ip_str = g_strdup (str); end_str = strchr (ip_str, '-'); if (end_str == NULL) { g_free (ip_str); return 0; } /* Separate the addresses. */ *end_str = '\0'; end_str++; if (!is_ipv6_address (ip_str) || *end_str == '\0') { g_free (ip_str); return 0; } p = end_str; /* Check that the 2nd part is at most 4 hexadecimal characters. */ while (isxdigit (*p) && p++); if (*p || p - end_str > 4) { g_free (ip_str); return 0; } g_free (ip_str); return 1; }
/** * @brief Checks if a buffer points to an IPv6 CIDR-exprpessed block. * "2620:0:2d0:200::7/120" is valid, "2620:0:2d0:200::7/129" is not. * * @param[in] str Buffer to check in. * * @return 1 if valid IPv6 CIDR-expressed block, 0 otherwise. */ static int is_cidr6_block (const char *str) { long block; char *addr6_str, *block_str, *p; addr6_str = g_strdup (str); block_str = strchr (addr6_str, '/'); if (block_str == NULL) { g_free (addr6_str); return 0; } /* Separate the address from the block value. */ *block_str = '\0'; block_str++; if (!is_ipv6_address (addr6_str) || !isdigit (*block_str)) { g_free (addr6_str); return 0; } p = NULL; block = strtol (block_str, &p, 10); g_free (addr6_str); if (*p || block <= 0 || block > 128) return 0; return 1; }
/** * @brief Determines the host type in a buffer. * * @param[in] str Buffer that contains host definition, could a be hostname, * single IPv4 or IPv6, CIDR-expressed block etc,. * * @return Host_TYPE_*, -1 if error. */ static int determine_host_type (const gchar *str_stripped) { /* * We have a single element with no leading or trailing * white spaces. This element could represent different host * definitions: single IPs, host names, CIDR-expressed blocks, * range-expressed networks, IPv6 addresses. */ /* Null or empty string. */ if (str_stripped == NULL || *str_stripped == '\0') return -1; /* Check for regular single IPv4 address. */ if (is_ipv4_address (str_stripped)) return HOST_TYPE_IPV4; /* Check for regular single IPv6 address. */ if (is_ipv6_address (str_stripped)) return HOST_TYPE_IPV6; /* Check for regular IPv4 CIDR-expressed block like "192.168.12.0/24" */ if (is_cidr_block (str_stripped)) return HOST_TYPE_CIDR_BLOCK; /* Check for short range-expressed networks "192.168.12.5-40" */ if (is_short_range_network (str_stripped)) return HOST_TYPE_RANGE_SHORT; /* Check for long range-expressed networks "192.168.1.0-192.168.3.44" */ if (is_long_range_network (str_stripped)) return HOST_TYPE_RANGE_LONG; /* Check for regular IPv6 CIDR-expressed block like "2620:0:2d0:200::7/120" */ if (is_cidr6_block (str_stripped)) return HOST_TYPE_CIDR6_BLOCK; /* Check for short range-expressed networks "::1-ef12" */ if (is_short_range6_network (str_stripped)) return HOST_TYPE_RANGE6_SHORT; /* Check for long IPv6 range-expressed networks like "::1:20:7-::1:25:3" */ if (is_long_range6_network (str_stripped)) return HOST_TYPE_RANGE6_LONG; /* Check for hostname. */ if (is_hostname (str_stripped)) return HOST_TYPE_NAME; /* @todo: If everything else fails, fallback to hostname ? */ return -1; }
/** * @brief Checks if a buffer points to a valid long IPv6 range-expressed * network. "::fee5-::1:530" is valid. * * @param[in] str Buffer to check in. * * @return 1 if valid long range-expressed network, 0 otherwise. */ static int is_long_range6_network (const char *str) { char *first_str, *second_str; int ret; first_str = g_strdup (str); second_str = strchr (first_str, '-'); if (second_str == NULL) { g_free (first_str); return 0; } /* Separate the addreses. */ *second_str = '\0'; second_str++; ret = is_ipv6_address (first_str) && is_ipv6_address (second_str); g_free (first_str); return ret; }
struct url_breakout *parse_url_string( char *url) { int rc = RC_NORMAL, stlen, port_number = NO_PORT; char *copy = 0, *protocol = 0, *user = 0, *domain = 0, *port = 0, *uri = 0, *query = 0, *pos = 0, *en_protocol = 0, *en_user = 0, *en_domain = 0, *st_port = 0, *st_query = 0, *next = 0, *scan_from = 0, *st_ipv6_port = 0, hold; struct url_breakout *parts = 0; copy = strdup( url); if( !copy) rc = ERR_MALLOC_FAILED; if( rc == RC_NORMAL) { parts = alloc_url_breakout(); if( !parts) rc = ERR_MALLOC_FAILED; } if( rc == RC_NORMAL) { scan_from = pos = copy; next = copy + strlen( copy); en_protocol = strstr( scan_from, PROTOCOL_DELIM); if( en_protocol) { scan_from = en_protocol + strlen( PROTOCOL_DELIM); next = en_protocol; } en_user = strstr( scan_from, USER_DELIM); en_domain = strstr( scan_from, DOMAIN_DELIM); if( en_user) { if( !en_domain) scan_from = en_user + 1; else if( en_user < en_domain) scan_from = en_user + 1; } st_port = strstr( scan_from, PORT_DELIM); st_query = strstr( scan_from, QUERY_DELIM); st_ipv6_port = strstr( scan_from, IPV6_PORT_DELIM); if( st_ipv6_port) { if( en_domain) { /* fixes the case: http://2601:9:5480:7d:59a8:fa5e:a8d2:c72d#8080/something.html */ /* also allows: http://www.foo.com#8080/something.html */ if( st_ipv6_port < en_domain) st_port = st_ipv6_port; } else if( st_query) { /* fixes the case: http://2601:9:5480:7d:59a8:fa5e:a8d2:c72d#8080?data=some */ /* also allows: http://www.foo.com#8080?data=some */ if( st_ipv6_port < st_query) st_port = st_ipv6_port; } /* fixes the case: http://2601:9:5480:7d:59a8:fa5e:a8d2:c72d#8080 */ /* also allows: http://www.foo.com#8080 */ else st_port = st_ipv6_port; } if( en_user) if( en_user < next) next = en_user; if( en_domain) if( en_domain < next) next = en_domain; if( st_port) if( st_port < next) next = st_port; if( st_query) if( st_query < next) next = st_query; } if( rc == RC_NORMAL && next == en_protocol) { hold = *en_protocol; *en_protocol = '\0'; protocol = strdup( pos); *en_protocol = hold; if( !protocol) rc = ERR_MALLOC_FAILED; else { pos = en_protocol + strlen( PROTOCOL_DELIM); next = pos + strlen( pos); if( en_user) if( en_user < next) next = en_user; if( en_domain) if( en_domain < next) next = en_domain; if( st_port) if( st_port < next) next = st_port; if( st_query) if( st_query < next) next = st_query; } } if( rc == RC_NORMAL && next == en_user) { hold = *en_user; *en_user = '******'; user = strdup( pos); *en_user = hold; if( !user) rc = ERR_MALLOC_FAILED; pos = en_user + 1; next = next + strlen( next); if( st_port) if( st_port < next) next = st_port; if( en_domain) if( en_domain < next) next = en_domain; if( st_query) if( st_query < next) next = st_query; } if( rc == RC_NORMAL && next == st_port) { /* This is annoying, but we need to see if the ":" we found was part * of an IPV6 address and not a ":port" suffixs on a domain or IPV4 * address. */ if( en_domain) { hold = *en_domain; *en_domain = '\0'; } if( is_ipv6_address( pos)) { st_port = 0; domain = strdup( pos); if( !domain) rc = ERR_MALLOC_FAILED; if( en_domain) { *en_domain = hold; pos = en_domain; } else pos = pos + strlen( pos); next = pos; } else { if( en_domain) *en_domain = hold; hold = *st_port; *st_port = '\0'; domain = strdup( pos); *st_port = hold; if( !domain) rc = ERR_MALLOC_FAILED; else { stlen = strlen( PORT_DELIM); pos = st_port + stlen; next = next + strlen( next); if( en_domain) if( en_domain < next) next = en_domain; if( st_query) if( st_query < next) next = st_query; hold = *next; *next = '\0'; port = strdup( pos); *next = hold; if( !port) rc = ERR_MALLOC_FAILED; pos = next; } } } if( rc == RC_NORMAL && next == en_domain) { if( !domain) { hold = *en_domain; *en_domain = '\0'; domain = strdup( pos); *en_domain = hold; if( !domain) rc = ERR_MALLOC_FAILED; pos = en_domain; } if( rc == RC_NORMAL) { if( !st_query) { uri = strdup( pos); pos = pos + strlen( pos); next = pos; } else { hold = *st_query; *st_query = '\0'; uri = strdup( pos); *st_query = hold; next = pos = st_query; } if( !uri) rc = ERR_MALLOC_FAILED; } } if( rc == RC_NORMAL && next == st_query) { if( !domain) { hold = *st_query; *st_query = '\0'; domain = strdup( pos); *st_query = hold; if( !domain) rc = ERR_MALLOC_FAILED; } if( rc == RC_NORMAL) { query = strdup( st_query + 1); if( !query) rc = ERR_MALLOC_FAILED; pos = pos + strlen( pos); next = pos; } } if( rc == RC_NORMAL && !domain && !*next && *pos) { domain = strdup( pos); if( !domain) rc = ERR_MALLOC_FAILED; pos = next; } if( rc == RC_NORMAL && port) { if( !isdigit( *port)) rc = ERR_INVALID_DATA; else { errno = 0; port_number = strtoul( port, &pos, BASE10); if( errno) rc = ERR_INVALID_DATA; else if( *pos) rc = ERR_INVALID_DATA; } } if( rc == RC_NORMAL && domain) { pos = strdup( domain); if( !pos) rc = ERR_MALLOC_FAILED; else if( is_ipv4_address( domain)) parts->ip4 = pos; else if( is_ipv6_address( domain)) parts->ip6 = pos; else parts->host = pos; } if( rc == RC_NORMAL) { if( !domain) parts->status = URL_ERROR; else if( !*domain) parts->status = URL_ERROR; else { parts->status = URL_VALID; parts->port = port_number; parts->protocol = protocol; parts->user = user; parts->target = domain; parts->uri = uri; parts->query = query; if( protocol) parts->use_ssl = !strcasecmp( protocol, SSL_PROT_PREFIX); protocol = user = domain = uri = query = 0; } } else if( parts) { parts->status = URL_ERROR; } if( protocol) free( protocol); if( user) free( user); if( domain) free( domain); if( uri) free( uri); if( query) free( query); if( port) free( port); if( copy) free( copy); return( parts); }