/** * 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 to be set by this function. * If the function is called with a name of @name_length zero it will clear * all server names set. * * 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 ret; gnutls_datum_t idn_name = {NULL,0}; 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; } ret = gnutls_idna_map(name, name_length, &idn_name, 0); if (ret < 0) { _gnutls_debug_log("unable to convert name %s to IDNA2003 format\n", (char*)name); return ret; } name = idn_name.data; name_length = idn_name.size; ret = _gnutls_server_name_set_raw(session, type, name, name_length); gnutls_free(idn_name.data); 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, on UTF-8 * decoding error %GNUTLS_E_IDNA_ERROR 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; gnutls_datum_t idn_name = {NULL,0}; extension_priv_data_t epriv; 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; ret = gnutls_idna_map((char*)priv->server_names[indx].name, priv->server_names[indx].name_length, &idn_name, 0); if (ret < 0) { _gnutls_debug_log("unable to convert name %s to IDNA2003 format\n", (char*)priv->server_names[indx].name); return GNUTLS_E_IDNA_ERROR; } if (*data_length > /* greater since we need one extra byte for the null */ idn_name.size) { *data_length = idn_name.size; memcpy(data, idn_name.data, *data_length); if (*type == GNUTLS_NAME_DNS) /* null terminate */ _data[(*data_length)] = 0; } else { *data_length = idn_name.size + 1; ret = GNUTLS_E_SHORT_MEMORY_BUFFER; goto cleanup; } ret = 0; cleanup: gnutls_free(idn_name.data); return ret; }
void socket_open(socket_st * hd, const char *hostname, const char *service, const char *app_proto, int flags, const char *msg, gnutls_datum_t *rdata) { struct addrinfo hints, *res, *ptr; int sd, err = 0; int udp = flags & SOCKET_FLAG_UDP; int ret; int fastopen = flags & SOCKET_FLAG_FASTOPEN; char buffer[MAX_BUF + 1]; char portname[16] = { 0 }; gnutls_datum_t idna; char *a_hostname; memset(hd, 0, sizeof(*hd)); if (flags & SOCKET_FLAG_VERBOSE) hd->verbose = 1; if (rdata) { hd->rdata.data = rdata->data; hd->rdata.size = rdata->size; } ret = gnutls_idna_map(hostname, strlen(hostname), &idna, 0); if (ret < 0) { fprintf(stderr, "Cannot convert %s to IDNA: %s\n", hostname, gnutls_strerror(ret)); exit(1); } hd->hostname = strdup(hostname); a_hostname = (char*)idna.data; if (msg != NULL) printf("Resolving '%s:%s'...\n", a_hostname, service); /* get server name */ memset(&hints, 0, sizeof(hints)); hints.ai_socktype = udp ? SOCK_DGRAM : SOCK_STREAM; if ((err = getaddrinfo(a_hostname, service, &hints, &res))) { fprintf(stderr, "Cannot resolve %s:%s: %s\n", hostname, service, gai_strerror(err)); exit(1); } sd = -1; for (ptr = res; ptr != NULL; ptr = ptr->ai_next) { sd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); if (sd == -1) continue; if ((err = getnameinfo(ptr->ai_addr, ptr->ai_addrlen, buffer, MAX_BUF, portname, sizeof(portname), NI_NUMERICHOST | NI_NUMERICSERV)) != 0) { fprintf(stderr, "getnameinfo(): %s\n", gai_strerror(err)); continue; } if (hints.ai_socktype == SOCK_DGRAM) { #if defined(IP_DONTFRAG) int yes = 1; if (setsockopt(sd, IPPROTO_IP, IP_DONTFRAG, (const void *) &yes, sizeof(yes)) < 0) perror("setsockopt(IP_DF) failed"); #elif defined(IP_MTU_DISCOVER) int yes = IP_PMTUDISC_DO; if (setsockopt(sd, IPPROTO_IP, IP_MTU_DISCOVER, (const void *) &yes, sizeof(yes)) < 0) perror("setsockopt(IP_DF) failed"); #endif } if (fastopen && ptr->ai_socktype == SOCK_STREAM && (ptr->ai_family == AF_INET || ptr->ai_family == AF_INET6)) { memcpy(&hd->connect_addr, ptr->ai_addr, ptr->ai_addrlen); hd->connect_addrlen = ptr->ai_addrlen; if (msg) printf("%s '%s:%s' (TFO)...\n", msg, buffer, portname); } else { if (msg) printf("%s '%s:%s'...\n", msg, buffer, portname); if ((err = connect(sd, ptr->ai_addr, ptr->ai_addrlen)) < 0) continue; } hd->fd = sd; if (flags & SOCKET_FLAG_STARTTLS) { hd->app_proto = app_proto; socket_starttls(hd); hd->app_proto = NULL; } if (!(flags & SOCKET_FLAG_SKIP_INIT)) { hd->session = init_tls_session(hostname); if (hd->session == NULL) { fprintf(stderr, "error initializing session\n"); exit(1); } } if (hd->session) { if (hd->rdata.data) { gnutls_session_set_data(hd->session, hd->rdata.data, hd->rdata.size); } gnutls_transport_set_int(hd->session, sd); } if (!(flags & SOCKET_FLAG_RAW) && !(flags & SOCKET_FLAG_SKIP_INIT)) { err = do_handshake(hd); if (err == GNUTLS_E_PUSH_ERROR) { /* failed connecting */ gnutls_deinit(hd->session); hd->session = NULL; continue; } else if (err < 0) { fprintf(stderr, "*** handshake has failed: %s\n", gnutls_strerror(err)); exit(1); } } break; } if (err != 0) { int e = errno; fprintf(stderr, "Could not connect to %s:%s: %s\n", buffer, portname, strerror(e)); exit(1); } if (sd == -1) { fprintf(stderr, "Could not find a supported socket\n"); exit(1); } if ((flags & SOCKET_FLAG_RAW) || (flags & SOCKET_FLAG_SKIP_INIT)) hd->secure = 0; else hd->secure = 1; hd->fd = sd; hd->ip = strdup(buffer); hd->service = strdup(portname); hd->ptr = ptr; hd->addr_info = res; hd->rdata.data = NULL; gnutls_free(idna.data); return; }