/** * Check if a label in UTF-8 format can be coded into valid IDNA. * This can fail if the ASCII-conversion becomes longer than 253 characters. * * @param name name to check (UTF-8 string) * @return #GNUNET_OK if the label can be converted to IDNA, * #GNUNET_SYSERR if the label is not valid for DNS names */ int GNUNET_DNSPARSER_check_name (const char *name) { char *ldup; char *output; size_t slen; char *tok; ldup = GNUNET_strdup (name); for (tok = strtok (ldup, "."); NULL != tok; tok = strtok (NULL, ".")) if (GNUNET_OK != GNUNET_DNSPARSER_check_label (tok)) { GNUNET_free (ldup); return GNUNET_SYSERR; } GNUNET_free (ldup); if (IDNA_SUCCESS != idna_to_ascii_8z (name, &output, IDNA_ALLOW_UNASSIGNED)) return GNUNET_SYSERR; slen = strlen (output); #if WINDOWS idn_free (output); #else free (output); #endif return (slen > 253) ? GNUNET_SYSERR : GNUNET_OK; }
wxString CControlSocket::ConvertDomainName(wxString const& domain) { #ifdef __WXMSW__ int len = IdnToAscii(IDN_ALLOW_UNASSIGNED, domain, domain.size() + 1, 0, 0); if( !len ) { LogMessage(MessageType::Debug_Warning, _T("Could not convert domain name")); return domain; } wchar_t* output = new wchar_t[len]; int res = IdnToAscii(IDN_ALLOW_UNASSIGNED, domain, domain.size() + 1, output, len); if( !res ) { LogMessage(MessageType::Debug_Warning, _T("Could not convert domain name")); return domain; } wxString ret(output); delete [] output; return ret; #else wxScopedCharBuffer const utf8 = domain.utf8_str(); char *output = 0; if (idna_to_ascii_8z(utf8, &output, IDNA_ALLOW_UNASSIGNED)) { LogMessage(MessageType::Debug_Warning, _T("Could not convert domain name")); return domain; } wxString result = wxConvCurrent->cMB2WX(output); idn_free(output); return result; #endif }
void doit (void) { int rc; char *out = NULL; size_t i; for (i = 0; i < sizeof (idna) / sizeof (idna[0]); i++) { rc = idna_to_unicode_8z8z (idna[i].in, &out, 0); if (rc != IDNA_SUCCESS) fail ("IDNA3[%ld] failed %d\n", i, rc); if (debug && rc == IDNA_SUCCESS) { printf ("input: %s\n", idna[i].in); printf ("computed out: %s\n", out); printf ("expected out: %s\n", idna[i].out); } if (strcmp (out, idna[i].out) != 0) fail ("IDNA3[%ld] failed\n", i); else if (debug) printf ("IDNA3[%ld] success\n", i); if (out) idn_free (out); } }
wxString CControlSocket::ConvertDomainName(wxString domain) { const wxWCharBuffer buffer = wxConvCurrent->cWX2WC(domain); int len = 0; while (buffer.data()[len]) len++; char *utf8 = new char[len * 2 + 2]; wxMBConvUTF8 conv; conv.WC2MB(utf8, buffer, len * 2 + 2); char *output; if (idna_to_ascii_8z(utf8, &output, IDNA_ALLOW_UNASSIGNED)) { delete [] utf8; LogMessage(::Debug_Warning, _T("Could not convert domain name")); return domain; } delete [] utf8; wxString result = wxConvCurrent->cMB2WX(output); idn_free(output); return result; }
int connect_to_ip (const ip_address *ip, int port, const char *print) { struct sockaddr_storage ss; struct sockaddr *sa = (struct sockaddr *)&ss; int sock; /* If PRINT is non-NULL, print the "Connecting to..." line, with PRINT being the host name we're connecting to. */ if (print) { const char *txt_addr = print_address (ip); if (0 != strcmp (print, txt_addr)) { char *str = NULL, *name; if (opt.enable_iri && (name = idn_decode ((char *) print)) != NULL) { int len = strlen (print) + strlen (name) + 4; str = xmalloc (len); snprintf (str, len, "%s (%s)", name, print); str[len-1] = '\0'; idn_free (name); } logprintf (LOG_VERBOSE, _("Connecting to %s|%s|:%d... "), str ? str : escnonprint_uri (print), txt_addr, port); xfree (str); } else { if (ip->family == AF_INET) logprintf (LOG_VERBOSE, _("Connecting to %s:%d... "), txt_addr, port); #ifdef ENABLE_IPV6 else if (ip->family == AF_INET6) logprintf (LOG_VERBOSE, _("Connecting to [%s]:%d... "), txt_addr, port); #endif } } /* Store the sockaddr info to SA. */ sockaddr_set_data (sa, ip, port); /* Create the socket of the family appropriate for the address. */ sock = socket (sa->sa_family, SOCK_STREAM, 0); if (sock < 0) goto err; #if defined(ENABLE_IPV6) && defined(IPV6_V6ONLY) if (opt.ipv6_only) { int on = 1; /* In case of error, we will go on anyway... */ int err = setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof (on)); IF_DEBUG if (err < 0) DEBUGP (("Failed setting IPV6_V6ONLY: %s", strerror (errno))); }
void doit (void) { char *badutf8 = strdup ("\x7e\x64\x61\x72\x10\x2f\x2f\xf9\x2b\x71" "\x60\x79\x7b\x2e\x63\x75\x2b\x61\x65\x72" "\x75\x65\x56\x66\x7f\x62\xc5\x76\xe5\x00"); char *s = NULL; int rc; rc = idna_to_ascii_8z (badutf8, &s, 0); free (badutf8); if (rc != IDNA_ICONV_ERROR) fail ("rc %d\n", rc); idn_free (s); }
/** * Check if a label in UTF-8 format can be coded into valid IDNA. * This can fail if the ASCII-conversion becomes longer than 63 characters. * * @param label label to check (UTF-8 string) * @return #GNUNET_OK if the label can be converted to IDNA, * #GNUNET_SYSERR if the label is not valid for DNS names */ int GNUNET_DNSPARSER_check_label (const char *label) { char *output; size_t slen; if (NULL != strchr (label, '.')) return GNUNET_SYSERR; /* not a label! Did you mean GNUNET_DNSPARSER_check_name? */ if (IDNA_SUCCESS != idna_to_ascii_8z (label, &output, IDNA_ALLOW_UNASSIGNED)) return GNUNET_SYSERR; slen = strlen (output); #if WINDOWS idn_free (output); #else free (output); #endif return (slen > 63) ? GNUNET_SYSERR : GNUNET_OK; }
/** * gnutls_server_name_set: * @session: is a #gnutls_session_t type. * @type: specifies the indicator type * @name: is a string that contains the server name. * @name_length: holds the length of name * * This function is to be used by clients that want to inform (via a * TLS extension mechanism) the server of the name they connected to. * This should be used by clients that connect to servers that do * virtual hosting. * * The value of @name depends on the @type type. In case of * %GNUTLS_NAME_DNS, a UTF-8 null-terminated domain name string, * without the trailing dot, is expected. * * IPv4 or IPv6 addresses are not permitted. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, * otherwise a negative error code is returned. **/ int gnutls_server_name_set(gnutls_session_t session, gnutls_server_name_type_t type, const void *name, size_t name_length) { int server_names, ret; server_name_ext_st *priv; extension_priv_data_t epriv; char *idn_name = NULL; int set = 0, rc; if (session->security_parameters.entity == GNUTLS_SERVER) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } if (name_length == 0) { /* unset extension */ _gnutls_ext_unset_session_data(session, GNUTLS_EXTENSION_SERVER_NAME); return 0; } #ifdef HAVE_LIBIDN rc = idna_to_ascii_8z (name, &idn_name, IDNA_ALLOW_UNASSIGNED); if (rc != IDNA_SUCCESS) { _gnutls_debug_log("unable to convert name %s to IDNA format: %s\n", (char*)name, idna_strerror(rc)); return GNUTLS_E_IDNA_ERROR; } name = idn_name; name_length = strlen(idn_name); #endif if (name_length > MAX_SERVER_NAME_SIZE) { ret = GNUTLS_E_SHORT_MEMORY_BUFFER; goto cleanup; } ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SERVER_NAME, &epriv); if (ret < 0) { set = 1; } if (set != 0) { priv = gnutls_calloc(1, sizeof(*priv)); if (priv == NULL) { gnutls_assert(); return GNUTLS_E_MEMORY_ERROR; } epriv = priv; } else priv = epriv; server_names = priv->server_names_size + 1; if (server_names > MAX_SERVER_NAME_EXTENSIONS) server_names = MAX_SERVER_NAME_EXTENSIONS; priv->server_names[server_names - 1].type = type; memcpy(priv->server_names[server_names - 1].name, name, name_length); priv->server_names[server_names - 1].name_length = name_length; priv->server_names_size = server_names; if (set != 0) _gnutls_ext_set_session_data(session, GNUTLS_EXTENSION_SERVER_NAME, epriv); ret = 0; cleanup: #ifdef HAVE_LIBIDN idn_free(idn_name); #endif return ret; }
/** * gnutls_server_name_get: * @session: is a #gnutls_session_t type. * @data: will hold the data * @data_length: will hold the data length. Must hold the maximum size of data. * @type: will hold the server name indicator type * @indx: is the index of the server_name * * This function will allow you to get the name indication (if any), a * client has sent. The name indication may be any of the enumeration * gnutls_server_name_type_t. * * If @type is GNUTLS_NAME_DNS, then this function is to be used by * servers that support virtual hosting, and the data will be a null * terminated IDNA ACE string (prior to GnuTLS 3.4.0 it was a UTF-8 string). * * If @data has not enough size to hold the server name * GNUTLS_E_SHORT_MEMORY_BUFFER is returned, and @data_length will * hold the required size. * * @index is used to retrieve more than one server names (if sent by * the client). The first server name has an index of 0, the second 1 * and so on. If no name with the given index exists * GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE is returned. * * Returns: On success, %GNUTLS_E_SUCCESS (0) is returned, * otherwise a negative error code is returned. **/ int gnutls_server_name_get(gnutls_session_t session, void *data, size_t * data_length, unsigned int *type, unsigned int indx) { char *_data = data; server_name_ext_st *priv; int ret; #ifdef HAVE_LIBIDN int rc; char *idn_name = NULL; #endif extension_priv_data_t epriv; gnutls_datum name; if (session->security_parameters.entity == GNUTLS_CLIENT) { gnutls_assert(); return GNUTLS_E_INVALID_REQUEST; } ret = _gnutls_ext_get_session_data(session, GNUTLS_EXTENSION_SERVER_NAME, &epriv); if (ret < 0) { gnutls_assert(); return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } priv = epriv; if (indx + 1 > priv->server_names_size) { return GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE; } *type = priv->server_names[indx].type; #ifdef HAVE_LIBIDN rc = idna_to_ascii_8z ((char*)priv->server_names[indx].name, &idn_name, IDNA_ALLOW_UNASSIGNED); if (rc != IDNA_SUCCESS) { _gnutls_debug_log("unable to convert name %s to IDNA format: %s\n", (char*)priv->server_names[indx].name, idna_strerror(rc)); return GNUTLS_E_IDNA_ERROR; } name.data = (unsigned char*)idn_name; name.size = strlen(idn_name); #else name.data = priv->server_names[indx].name; name.size = priv->server_names[indx].name_length; #endif if (*data_length > /* greater since we need one extra byte for the null */ name.size) { *data_length = name.size; memcpy(data, name.data, *data_length); if (*type == GNUTLS_NAME_DNS) /* null terminate */ _data[(*data_length)] = 0; } else { *data_length = name.size + 1; ret = GNUTLS_E_SHORT_MEMORY_BUFFER; goto cleanup; } ret = 0; cleanup: #ifdef HAVE_LIBIDN idn_free(idn_name); #endif return ret; }
/** * Add a DNS name to the UDP packet at the given location, converting * the name to IDNA notation as necessary. * * @param dst where to write the name (UDP packet) * @param dst_len number of bytes in @a dst * @param off pointer to offset where to write the name (increment by bytes used) * must not be changed if there is an error * @param name name to write * @return #GNUNET_SYSERR if @a name is invalid * #GNUNET_NO if @a name did not fit * #GNUNET_OK if @a name was added to @a dst */ int GNUNET_DNSPARSER_builder_add_name (char *dst, size_t dst_len, size_t *off, const char *name) { const char *dot; const char *idna_name; char *idna_start; size_t start; size_t pos; size_t len; Idna_rc rc; if (NULL == name) return GNUNET_SYSERR; if (IDNA_SUCCESS != (rc = idna_to_ascii_8z (name, &idna_start, IDNA_ALLOW_UNASSIGNED))) { GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to convert UTF-8 name `%s' to DNS IDNA format: %s\n"), name, idna_strerror (rc)); return GNUNET_NO; } idna_name = idna_start; start = *off; if (start + strlen (idna_name) + 2 > dst_len) goto fail; pos = start; do { dot = strchr (idna_name, '.'); if (NULL == dot) len = strlen (idna_name); else len = dot - idna_name; if ( (len >= 64) || (0 == len) ) { GNUNET_break (0); goto fail; /* segment too long or empty */ } dst[pos++] = (char) (uint8_t) len; GNUNET_memcpy (&dst[pos], idna_name, len); pos += len; idna_name += len + 1; /* also skip dot */ } while (NULL != dot); dst[pos++] = '\0'; /* terminator */ *off = pos; #if WINDOWS idn_free (idna_start); #else free (idna_start); #endif return GNUNET_OK; fail: #if WINDOWS idn_free (idna_start); #else free (idna_start); #endif return GNUNET_NO; }
/** * Parse name inside of a DNS query or record. * * @param udp_payload entire UDP payload * @param udp_payload_length length of @a udp_payload * @param off pointer to the offset of the name to parse in the udp_payload (to be * incremented by the size of the name) * @param depth current depth of our recursion (to prevent stack overflow) * @return name as 0-terminated C string on success, NULL if the payload is malformed */ static char * parse_name (const char *udp_payload, size_t udp_payload_length, size_t *off, unsigned int depth) { const uint8_t *input = (const uint8_t *) udp_payload; char *ret; char *tmp; char *xstr; uint8_t len; size_t xoff; char *utf8; Idna_rc rc; ret = GNUNET_strdup (""); while (1) { if (*off >= udp_payload_length) { GNUNET_break_op (0); goto error; } len = input[*off]; if (0 == len) { (*off)++; break; } if (len < 64) { if (*off + 1 + len > udp_payload_length) { GNUNET_break_op (0); goto error; } GNUNET_asprintf (&tmp, "%.*s", (int) len, &udp_payload[*off + 1]); if (IDNA_SUCCESS != (rc = idna_to_unicode_8z8z (tmp, &utf8, IDNA_ALLOW_UNASSIGNED))) { GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Failed to convert DNS IDNA name `%s' to UTF-8: %s\n"), tmp, idna_strerror (rc)); GNUNET_free (tmp); GNUNET_asprintf (&tmp, "%s%.*s.", ret, (int) len, &udp_payload[*off + 1]); } else { GNUNET_free (tmp); GNUNET_asprintf (&tmp, "%s%s.", ret, utf8); #if WINDOWS idn_free (utf8); #else free (utf8); #endif } GNUNET_free (ret); ret = tmp; *off += 1 + len; } else if ((64 | 128) == (len & (64 | 128)) ) { if (depth > 32) { GNUNET_break_op (0); goto error; /* hard bound on stack to prevent "infinite" recursion, disallow! */ } /* pointer to string */ if (*off + 1 > udp_payload_length) { GNUNET_break_op (0); goto error; } xoff = ((len - (64 | 128)) << 8) + input[*off+1]; xstr = parse_name (udp_payload, udp_payload_length, &xoff, depth + 1); if (NULL == xstr) { GNUNET_break_op (0); goto error; } GNUNET_asprintf (&tmp, "%s%s.", ret, xstr); GNUNET_free (ret); GNUNET_free (xstr); ret = tmp; if (strlen (ret) > udp_payload_length) { GNUNET_break_op (0); goto error; /* we are looping (building an infinite string) */ } *off += 2; /* pointers always terminate names */ break; } else { /* neither pointer nor inline string, not supported... */ GNUNET_break_op (0); goto error; } } if (0 < strlen(ret)) ret[strlen(ret)-1] = '\0'; /* eat tailing '.' */ return ret; error: GNUNET_break_op (0); GNUNET_free (ret); return NULL; }
struct address_list * lookup_host (const char *host, int flags) { struct address_list *al; bool silent = !!(flags & LH_SILENT); bool use_cache; bool numeric_address = false; double timeout = opt.dns_timeout; #ifndef ENABLE_IPV6 /* If we're not using getaddrinfo, first check if HOST specifies a numeric IPv4 address. Some implementations of gethostbyname (e.g. the Ultrix one and possibly Winsock) don't accept dotted-decimal IPv4 addresses. */ { uint32_t addr_ipv4 = (uint32_t)inet_addr (host); if (addr_ipv4 != (uint32_t) -1) { /* No need to cache host->addr relation, just return the address. */ char *vec[2]; vec[0] = (char *)&addr_ipv4; vec[1] = NULL; return address_list_from_ipv4_addresses (vec); } } #else /* ENABLE_IPV6 */ /* If we're using getaddrinfo, at least check whether the address is already numeric, in which case there is no need to print the "Resolving..." output. (This comes at no additional cost since the is_valid_ipv*_address are already required for url_parse.) */ { const char *end = host + strlen (host); if (is_valid_ipv4_address (host, end) || is_valid_ipv6_address (host, end)) numeric_address = true; } #endif /* Cache is normally on, but can be turned off with --no-dns-cache. Don't cache passive lookups under IPv6. */ use_cache = opt.dns_cache; #ifdef ENABLE_IPV6 if ((flags & LH_BIND) || numeric_address) use_cache = false; #endif /* Try to find the host in the cache so we don't need to talk to the resolver. If LH_REFRESH is requested, remove HOST from the cache instead. */ if (use_cache) { if (!(flags & LH_REFRESH)) { al = cache_query (host); if (al) return al; } else cache_remove (host); } /* No luck with the cache; resolve HOST. */ if (!silent && !numeric_address) { char *str = NULL, *name; if (opt.enable_iri && (name = idn_decode ((char *) host)) != NULL) { int len = strlen (host) + strlen (name) + 4; str = xmalloc (len); snprintf (str, len, "%s (%s)", name, host); str[len-1] = '\0'; idn_free (name); } logprintf (LOG_VERBOSE, _("Resolving %s... "), quotearg_style (escape_quoting_style, str ? str : host)); xfree (str); } #ifdef ENABLE_IPV6 { int err; struct addrinfo hints, *res; xzero (hints); hints.ai_socktype = SOCK_STREAM; if (opt.ipv4_only) hints.ai_family = AF_INET; else if (opt.ipv6_only) hints.ai_family = AF_INET6; else /* We tried using AI_ADDRCONFIG, but removed it because: it misinterprets IPv6 loopbacks, it is broken on AIX 5.1, and it's unneeded since we sort the addresses anyway. */ hints.ai_family = AF_UNSPEC; if (flags & LH_BIND) hints.ai_flags |= AI_PASSIVE; #ifdef AI_NUMERICHOST if (numeric_address) { /* Where available, the AI_NUMERICHOST hint can prevent costly access to DNS servers. */ hints.ai_flags |= AI_NUMERICHOST; timeout = 0; /* no timeout needed when "resolving" numeric hosts -- avoid setting up signal handlers and such. */ } #endif err = getaddrinfo_with_timeout (host, NULL, &hints, &res, timeout); if (err != 0 || res == NULL) { if (!silent) logprintf (LOG_VERBOSE, _("failed: %s.\n"), err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno)); return NULL; } al = address_list_from_addrinfo (res); freeaddrinfo (res); if (!al) { logprintf (LOG_VERBOSE, _("failed: No IPv4/IPv6 addresses for host.\n")); return NULL; } /* Reorder addresses so that IPv4 ones (or IPv6 ones, as per --prefer-family) come first. Sorting is stable so the order of the addresses with the same family is undisturbed. */ if (al->count > 1 && opt.prefer_family != prefer_none) stable_sort (al->addresses, al->count, sizeof (ip_address), opt.prefer_family == prefer_ipv4 ? cmp_prefer_ipv4 : cmp_prefer_ipv6); } #else /* not ENABLE_IPV6 */ { struct hostent *hptr = gethostbyname_with_timeout (host, timeout); if (!hptr) { if (!silent) { if (errno != ETIMEDOUT) logprintf (LOG_VERBOSE, _("failed: %s.\n"), host_errstr (h_errno)); else logputs (LOG_VERBOSE, _("failed: timed out.\n")); } return NULL; } /* Do older systems have h_addr_list? */ al = address_list_from_ipv4_addresses (hptr->h_addr_list); } #endif /* not ENABLE_IPV6 */ /* Print the addresses determined by DNS lookup, but no more than three if show_all_dns_entries is not specified. */ if (!silent && !numeric_address) { int i; int printmax = al->count; if (!opt.show_all_dns_entries && printmax > 3) printmax = 3; for (i = 0; i < printmax; i++) { logputs (LOG_VERBOSE, print_address (al->addresses + i)); if (i < printmax - 1) logputs (LOG_VERBOSE, ", "); } if (printmax != al->count) logputs (LOG_VERBOSE, ", ..."); logputs (LOG_VERBOSE, "\n"); } /* Cache the lookup information. */ if (use_cache) cache_store (host, al); return al; }
/* This function takes a hesiod (name, type) and returns a DNS * name which is to be resolved. */ char *hesiod_to_bind(void *context, const char *name, const char *type) { struct hesiod_p *ctx = (struct hesiod_p *) context; char bindname[MAXDNAME], *p, *ret, *idn_ret, **rhs_list = NULL; const char *rhs; int len, rc; if (strlen(name) > sizeof(bindname) - 1) { errno = EMSGSIZE; return NULL; } strcpy(bindname, name); /* Find the right right hand side to use, possibly truncating bindname. */ p = strchr(bindname, '@'); if (p) { *p++ = 0; if (strchr(p, '.')) rhs = name + (p - bindname); else { rhs_list = hesiod_resolve(context, p, "rhs-extension"); if (rhs_list) rhs = *rhs_list; else { errno = ENOENT; return NULL; } } } else rhs = ctx->rhs; /* See if we have enough room. */ len = strlen(bindname) + 1 + strlen(type); if (ctx->lhs) len += strlen(ctx->lhs) + ((ctx->lhs[0] != '.') ? 1 : 0); len += strlen(rhs) + ((rhs[0] != '.') ? 1 : 0); if (len > sizeof(bindname) - 1) { if (rhs_list) hesiod_free_list(context, rhs_list); errno = EMSGSIZE; return NULL; } /* Put together the rest of the domain. */ strcat(bindname, "."); strcat(bindname, type); if (ctx->lhs) { if (ctx->lhs[0] != '.') strcat(bindname, "."); strcat(bindname, ctx->lhs); } if (rhs[0] != '.') strcat(bindname, "."); strcat(bindname, rhs); /* rhs_list is no longer needed, since we're done with rhs. */ if (rhs_list) hesiod_free_list(context, rhs_list); /* Make a copy of the result and return it to the caller. */ #ifdef HAVE_LIBIDN rc = idna_to_ascii_lz(bindname, &idn_ret, 0); if (rc != IDNA_SUCCESS) { errno = EINVAL; return NULL; } ret = strdup(idn_ret); idn_free(idn_ret); #else ret = strdup(bindname); #endif if (!ret) { errno = ENOMEM; return NULL; } return ret; }