static ssh_dns_resolver_get_2k(SshDNSResolver resolver) { HMODULE module; p_get_interface_info get_interface_info; p_get_per_adapter_info get_per_adapter_info; IP_INTERFACE_INFO *interface_info; IP_ADAPTER_INDEX_MAP *adapter_map; IP_PER_ADAPTER_INFO *adapter_info; IP_ADDR_STRING *addr_string; SshInt32 count; SshUInt32 result; SshUInt32 info_len = 0; Boolean added = FALSE; SshIpAddrStruct address[1]; module = LoadLibrary(TEXT("iphlpapi")); if (module == NULL) { SSH_DEBUG(SSH_D_FAIL, ("Unable to load iphelper library")); return FALSE; } get_interface_info = (p_get_interface_info)GetProcAddress(module, TEXT("GetInterfaceInfo")); get_per_adapter_info = (p_get_per_adapter_info)GetProcAddress(module, TEXT("GetPerAdapterInfo")); if (get_interface_info == NULL || get_per_adapter_info == NULL) { SSH_DEBUG(SSH_D_FAIL, ("Could not find necessary" " functions in the library")); goto exit_function; } result = get_interface_info(NULL, &info_len); if (ERROR_INSUFFICIENT_BUFFER != result) { SSH_DEBUG(SSH_D_FAIL, ("Unable to get the size of Interface info. Error is %d", result)); goto exit_function; } interface_info = ssh_calloc(1, info_len); if (NULL == interface_info) { SSH_DEBUG(SSH_D_FAIL, ("Unable to allocate memory")); goto exit_function; } result = get_interface_info(interface_info, &info_len); if (NO_ERROR != result) { SSH_DEBUG(SSH_D_FAIL, ("Failed to Get Interface information. Error is %d", result)); goto exit_function; } for (count = 0; count < interface_info->NumAdapters; count++) { adapter_map = (IP_ADAPTER_INDEX_MAP *)&(interface_info->Adapter[count]); info_len = 0; result = get_per_adapter_info(adapter_map->Index, NULL, &info_len); if (ERROR_BUFFER_OVERFLOW == result) { adapter_info = ssh_calloc(1, info_len); if (NULL == adapter_info) { SSH_DEBUG(SSH_D_FAIL, ("Unable to allocate memory")); break; } result = get_per_adapter_info(adapter_map->Index, adapter_info, &info_len); if (NO_ERROR == result) { addr_string = &(adapter_info->DnsServerList); while (addr_string !=NULL) { if (ssh_ipaddr_parse(address, addr_string->IpAddress.String)) { ssh_dns_resolver_safety_belt_add(resolver, 1, address); added = TRUE; SSH_DEBUG(SSH_D_NICETOKNOW, ("Added DNS server %@", ssh_ipaddr_render, address)); } addr_string = addr_string->Next; } } else { /* Failed for this adapter. Lets continue for other adapters */ SSH_DEBUG(SSH_D_FAIL, ("Failed to get adapter info for index %d. " "Error is %d", count, result)); } ssh_free(adapter_info); } else { SSH_DEBUG(SSH_D_FAIL, ("Failed to get adapter info len for index %d. " "Error is %d", count, result)); } } exit_function: ssh_free(interface_info); FreeLibrary(module); return added; }
/* Create a child dst_entry with locked interface MTU, and attach it to `dst'. This is needed on newer linux kernels and IP_ONLY_INTERCEPTOR builds, where the IP stack fragments packets to path MTU after ssh_interceptor_send. */ static struct dst_entry * interceptor_route_create_child_dst(struct dst_entry *dst, Boolean ipv6) { struct dst_entry *child; #ifdef LINUX_HAS_DST_COPY_METRICS SshUInt32 set; struct rt6_info *rt6; struct rtable *rt; #endif /* LINUX_HAS_DST_COPY_METRICS */ /* Allocate a dst_entry and copy relevant fields from dst. */ child = SSH_DST_ALLOC(dst); if (child == NULL) return NULL; child->input = dst->input; child->output = dst->output; /* Child is not added to dst hash, and linux native IPsec is disabled. */ child->flags |= (DST_NOHASH | DST_NOPOLICY | DST_NOXFRM); /* Copy route metrics and lock MTU to interface MTU. */ #ifdef LINUX_HAS_DST_COPY_METRICS if (ipv6 == TRUE) { rt6 = (struct rt6_info *)child; memset(&rt6->rt6i_table, 0, sizeof(*rt6) - sizeof(struct dst_entry)); } else { rt = (struct rtable *)child; memset(&SSH_RTABLE_FIRST_MEMBER(rt), 0, sizeof(*rt) - sizeof(struct dst_entry)); } dst_copy_metrics(child, dst); set = dst_metric(child, RTAX_LOCK); set |= 1 << RTAX_MTU; dst_metric_set(child, RTAX_LOCK, set); #else /* LINUX_HAS_DST_COPY_METRICS */ memcpy(child->metrics, dst->metrics, sizeof(child->metrics)); child->metrics[RTAX_LOCK-1] |= 1 << RTAX_MTU; #endif /* LINUX_HAS_DST_COPY_METRICS */ #ifdef CONFIG_NET_CLS_ROUTE child->tclassid = dst->tclassid; #endif /* CONFIG_NET_CLS_ROUTE */ #ifdef CONFIG_XFRM child->xfrm = NULL; #endif /* CONFIG_XFRM */ #ifdef LINUX_HAS_HH_CACHE if (dst->hh) { atomic_inc(&dst->hh->hh_refcnt); child->hh = dst->hh; } #endif /* LINUX_HAS_HH_CACHE */ #ifdef LINUX_HAS_DST_NEIGHBOUR_FUNCTIONS if (dst_get_neighbour(dst) != NULL) dst_set_neighbour(child, neigh_clone(dst_get_neighbour(dst))); #else /* LINUX_HAS_DST_NEIGHBOUR_FUNCTIONS */ if (dst->neighbour != NULL) child->neighbour = neigh_clone(dst->neighbour); #endif /* LINUX_HAS_DST_NEIGHBOUR_FUNCTIONS */ if (dst->dev) { dev_hold(dst->dev); child->dev = dst->dev; } SSH_ASSERT(dst->child == NULL); dst->child = dst_clone(child); SSH_DEBUG(SSH_D_MIDOK, ("Allocated child %p dst_entry for dst %p mtu %d", child, dst, dst_mtu(dst))); return child; }
/* * Parse incoming socks connection from buffer. Consume the request * packet data from buffer. If everything is ok it allocates SocksInfo * strcture and store the request fields in it (sets * socks_version_number, command_code, ip, port, username). Returns * SSH_SOCKS_SUCCESS, SSH_SOCKS_TRY_AGAIN, or SSH_SOCKS_ERROR_*. If * anything other than SSH_SOCKS_SUCCESS is returned the socksinfo is * set to NULL. Use ssh_socks_free to free socksinfo data. */ SocksError ssh_socks_server_parse_open(SshBuffer buffer, SocksInfo *socksinfo) { unsigned char *data, *ip; unsigned long i, port; unsigned int version, cmd, ip_addr_len, atyp; unsigned char *username = NULL; size_t ret, len, bytes = 0; *socksinfo = NULL; len = ssh_buffer_len(buffer); data = ssh_buffer_ptr(buffer); if (len < 1) return SSH_SOCKS_TRY_AGAIN; version = data[0]; bytes++; if (version != 4 && version != 5) { SSH_DEBUG(2, ("Server gave us version %d.", version)); return SSH_SOCKS_ERROR_UNSUPPORTED_SOCKS_VERSION; } if (version == 4) { /* Check if enough data for header and name */ if (len < SOCKS4_COMMAND_SIZE + 1) { return SSH_SOCKS_TRY_AGAIN; } /* Find the end of username */ for (i = SOCKS4_COMMAND_SIZE; i < len; i++) { if (data[i] == '\0') break; } /* End of username not found, return either error or try_again */ if (i == len || data[i] != '\0') { if (len > SOCKS4_COMMAND_SIZE + SOCKS4_MAX_NAME_LEN) { return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } return SSH_SOCKS_TRY_AGAIN; } cmd = data[1]; port = SSH_GET_16BIT(&data[2]); ip_addr_len = 4; ip = ssh_memdup(&data[4], ip_addr_len); atyp = SSH_SOCKS5_ATYP_IPV4; if (ip == NULL) { SSH_DEBUG(2, ("Failed to allocate IP-address buffer.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } username = ssh_strdup((char *)(data + SOCKS4_COMMAND_SIZE)); bytes = SOCKS4_COMMAND_SIZE + strlen((char *) data + SOCKS4_COMMAND_SIZE) + 1; } else { unsigned char port_buf[2]; if (len - bytes < 3) return SSH_SOCKS_TRY_AGAIN; ret = ssh_decode_array(data + bytes, len - bytes, SSH_DECODE_CHAR(&cmd), SSH_DECODE_CHAR(NULL), /* RSV */ SSH_DECODE_CHAR(&atyp), SSH_FORMAT_END); if (ret <= 0) { SSH_DEBUG(2, ("Failed to decode command packet.")); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } bytes += ret; if (atyp == SSH_SOCKS5_ATYP_IPV4) { SSH_DEBUG(4, ("SOCKS5 received address type IPV4.")); ip_addr_len = 4; } else if (atyp == SSH_SOCKS5_ATYP_IPV6) { SSH_DEBUG(4, ("SOCKS5 received address type IPV6.")); ip_addr_len = 16; } else if (atyp == SSH_SOCKS5_ATYP_FQDN) { if (len - bytes < 1) return SSH_SOCKS_TRY_AGAIN; ip_addr_len = *(data + bytes); if (ip_addr_len <= 0 || ip_addr_len >= 255) { SSH_DEBUG(2, ("Invalid FQDN address len %d.", ip_addr_len)); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } SSH_DEBUG(4, ("SOCKS5 received address type FQDN, len %d.", ip_addr_len)); bytes++; } else { SSH_DEBUG(2, ("Invalid address type %d.", atyp)); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } /* ip addr len + port */ if (len - bytes < ip_addr_len + 2) return SSH_SOCKS_TRY_AGAIN; ip = ssh_calloc(ip_addr_len + 1, sizeof(unsigned char)); if (ip == NULL) { SSH_DEBUG(2, ("Failed to allocate IP-address buffer.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } ret = ssh_decode_array(data + bytes, len - bytes, SSH_DECODE_DATA(ip, ip_addr_len), SSH_DECODE_DATA(port_buf, 2), SSH_FORMAT_END); if (ret <= 0) { SSH_DEBUG(2, ("Failed to decode command packet.")); ssh_free(ip); return SSH_SOCKS_ERROR_PROTOCOL_ERROR; } port = SSH_GET_16BIT(port_buf); bytes += ret; } if ((*socksinfo = ssh_calloc(1, sizeof(struct SocksInfoRec))) == NULL) { SSH_DEBUG(2, ("Failed to allocate SocksInfo.")); ssh_free(ip); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } if (atyp == SSH_SOCKS5_ATYP_FQDN) { (*socksinfo)->ip = ip; } else { SshIpAddrStruct ip_addr; unsigned char buf[SSH_IP_ADDR_STRING_SIZE]; SSH_IP_DECODE(&ip_addr, ip, ip_addr_len); ssh_ipaddr_print(&ip_addr, buf, sizeof(buf)); (*socksinfo)->ip = ssh_memdup(buf, ssh_ustrlen(buf)); ssh_free(ip); if ((*socksinfo)->ip == NULL) { SSH_DEBUG(2, ("Failed to allocate final IP-addr buf.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } } (*socksinfo)->socks_version_number = version; (*socksinfo)->command_code = cmd; ssh_dsprintf(&(*socksinfo)->port, "%lu", port); (*socksinfo)->username = username; ssh_buffer_consume(buffer, bytes); SSH_DEBUG(5, ("Decoded %zd bytes.", bytes)); return SSH_SOCKS_SUCCESS; }
static SshEngineActionRet engine_packet_handler_verify_sa_selectors(SshEngine engine, SshEnginePacketContext pc) { unsigned char src_ip[SSH_IP_ADDR_SIZE], dst_ip[SSH_IP_ADDR_SIZE]; SshUInt16 src_port, dst_port; size_t ip_len; SshEngineTransformControl c_trd; SshUInt32 rule_index; SshEnginePolicyRule rule; #ifdef SSHDIST_L2TP SshEngineTransformData d_trd; #endif /* SSHDIST_L2TP */ SSH_ASSERT(pc->pp != NULL); SSH_ASSERT(pc->prev_transform_index != SSH_IPSEC_INVALID_INDEX); ssh_kernel_mutex_assert_is_locked(engine->flow_control_table_lock); SSH_DEBUG(SSH_D_MIDOK, ("Verifying that decapsulated packet matches the SA selectors " "of transform 0x%lx", (unsigned long) pc->prev_transform_index)); /* Fetch transform used for decapsulation. */ c_trd = SSH_ENGINE_GET_TRD(engine, pc->prev_transform_index); if (c_trd == NULL) { SSH_DEBUG(SSH_D_FAIL, ("Transform has 0x%lx disappeared for decapsulated packet", (unsigned long) pc->prev_transform_index)); SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP); return SSH_ENGINE_RET_FAIL; } #ifdef SSHDIST_L2TP d_trd = FASTPATH_GET_READ_ONLY_TRD(engine->fastpath, pc->prev_transform_index); if (d_trd->transform & SSH_PM_IPSEC_L2TP) { FASTPATH_RELEASE_TRD(engine->fastpath, pc->prev_transform_index); SSH_DEBUG(SSH_D_LOWOK, ("Skipping SA selector check for l2tp packet")); return SSH_ENGINE_RET_OK; } FASTPATH_RELEASE_TRD(engine->fastpath, pc->prev_transform_index); #endif /* SSHDIST_L2TP */ engine_packet_handler_lookup_prepare(pc, src_ip, &src_port, dst_ip, &dst_port, &ip_len); /* Find APPLY rule to the transform. */ for (rule_index = c_trd->rules; rule_index != SSH_IPSEC_INVALID_INDEX; rule_index = rule->trd_next) { rule = SSH_ENGINE_GET_RULE(engine, rule_index); SSH_ASSERT(rule != NULL); if (rule->type == SSH_ENGINE_RULE_APPLY) { /* Compare packet 5-tupple to SA selectors in APPLY rule. Note that APPLY rule is for reverse direction, thus packet source/destination addresses and ports must be compared to the opposite rule selector. */ if (rule->protocol != pc->pp->protocol) { SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: protocol mismatch", (int) rule_index)); continue; } if ((rule->selectors & SSH_SELECTOR_SRCIP) && (memcmp(rule->src_ip_low, dst_ip, ip_len) > 0 || memcmp(rule->src_ip_high, dst_ip, ip_len) < 0)) { SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: destination IP mismatch", (int) rule_index)); continue; } if ((rule->selectors & SSH_SELECTOR_DSTIP) && (memcmp(rule->dst_ip_low, src_ip, ip_len) > 0 || memcmp(rule->dst_ip_high, src_ip, ip_len) < 0)) { SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: source IP mismatch", (int) rule_index)); continue; } if ((rule->selectors & SSH_SELECTOR_IPPROTO) && rule->ipproto != pc->ipproto) { SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: IP protocol mismatch", (int) rule_index)); continue; } if ((rule->selectors & SSH_SELECTOR_SRCPORT) && (rule->src_port_low > dst_port || rule->src_port_high < dst_port)) { SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: destination port mismatch", (int) rule_index)); continue; } if (rule->selectors & SSH_SELECTOR_DSTPORT) { if ((rule->selectors & SSH_SELECTOR_ICMPTYPE) && ((rule->dst_port_low & 0xff00) != (dst_port & 0xff00))) { SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: ICMP type mismatch", (int) rule_index)); continue; } if ((rule->selectors & SSH_SELECTOR_ICMPCODE) && ((rule->dst_port_low & 0x00ff) != (dst_port & 0x00ff))) { SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: ICMP code mismatch", (int) rule_index)); continue; } if ((rule->selectors & (SSH_SELECTOR_ICMPTYPE | SSH_SELECTOR_ICMPCODE)) == 0 && (rule->dst_port_low > src_port || rule->dst_port_high < src_port)) { SSH_DEBUG(SSH_D_LOWOK, ("Rule %d: source port mismatch", (int) rule_index)); continue; } } /* Packet fits into SA selectors. */ SSH_DEBUG(SSH_D_MIDOK, ("Rule %d: decapsulated packet matches SA selectors", (int) rule_index)); return SSH_ENGINE_RET_OK; } } SSH_ASSERT(rule_index == SSH_IPSEC_INVALID_INDEX); SSH_DEBUG(SSH_D_MIDOK, ("Decapsulated packet does not match the SA selectors, " "dropping packet.")); pc->audit.corruption = SSH_PACKET_CORRUPTION_IPSEC_INVALID_SELECTORS; return SSH_ENGINE_RET_DROP; }
/* pc -> quadruple */ static void engine_packet_handler_lookup_prepare(SshEnginePacketContext pc, unsigned char *srcip, SshUInt16 *sport, unsigned char *dstip, SshUInt16 *dport, size_t *len) { SSH_IP_ENCODE(&pc->src, srcip, *len); SSH_IP_ENCODE(&pc->dst, dstip, *len); switch (pc->ipproto) { case SSH_IPPROTO_TCP: case SSH_IPPROTO_UDP: case SSH_IPPROTO_UDPLITE: case SSH_IPPROTO_SCTP: *sport = pc->u.rule.src_port; *dport = pc->u.rule.dst_port; break; case SSH_IPPROTO_ICMP: case SSH_IPPROTO_IPV6ICMP: *sport = 0; *dport = (pc->icmp_type << 8) | pc->u.rule.icmp_code; break; default: *sport = *dport = 0; break; } #ifdef DEBUG_LIGHT { int i; char ipproto_buf[50]; SshUInt32 pc_flags = 0; SshUInt32 pp_flags = 0; for (i = 0; ssh_ip_protocol_id_keywords[i].name; i++) if (ssh_ip_protocol_id_keywords[i].code == pc->ipproto) { ssh_snprintf(ipproto_buf, sizeof(ipproto_buf), "%s", ssh_ip_protocol_id_keywords[i].name); break; } if (ssh_ip_protocol_id_keywords[i].name == NULL) ssh_snprintf(ipproto_buf, sizeof(ipproto_buf), "(unknown %u)", (unsigned int) pc->ipproto); pc_flags = pc->flags; if (pc->pp) pp_flags = pc->pp->flags; SSH_DEBUG(SSH_D_HIGHSTART, ("Rule lookup prepare: src=%@ dst=%@ ipproto=%s " "srcport=%d dstport=%d pc->flags=0x%x " "pp->flags=0x%x", ssh_ipaddr_render, &pc->src, ssh_ipaddr_render, &pc->dst, ipproto_buf, (int) *sport, (int) *dport, (unsigned int) pc_flags, (unsigned int) pp_flags)); } #endif /* DEBUG_LIGHT */ }
/* Export given IKE SA pointed by negotiation to buffer. Buffer is NOT cleared before the export. Returns size of packet added to the buffer, or 0 in case of error. In case of error the data added to the buffer is removed. */ size_t ssh_ike_sa_export(SshBuffer buffer, SshIkeNegotiation negotiation) { SshIkeNegotiation ike_negotiation; SshIkePMPhaseI pm_info; SshIkeSA sa; size_t orig_len; size_t item_len; size_t len; SSH_DEBUG(5, ("Start")); orig_len = ssh_buffer_len(buffer); len = 0; sa = negotiation->sa; if (sa == NULL) { SSH_DEBUG(3, ("Trying to export SA that is deleted")); goto error; } if (sa->lock_flags != 0) { SSH_DEBUG(3, ("Trying to export SA whose lock_flags is not 0")); goto error; } if (!sa->phase_1_done) { SSH_DEBUG(3, ("Trying to export IKE SA which is not ready yet")); goto error; } ike_negotiation = sa->isakmp_negotiation; pm_info = ike_negotiation->ike_pm_info; if (ike_negotiation->notification_state != SSH_IKE_NOTIFICATION_STATE_ALREADY_SENT) { SSH_DEBUG(3, ("Trying to export IKE SA which hasn't call callback yet")); goto error; } if ((ike_negotiation->lock_flags & ~SSH_IKE_NEG_LOCK_FLAG_WAITING_FOR_DONE) != 0) { SSH_DEBUG(3, ("Trying to export IKE SA whose neg lock_flags are not 0")); goto error; } item_len = ssh_encode_buffer (buffer, /* Magic number */ SSH_ENCODE_UINT32((SshUInt32) SSH_IKE_EXPORT_MAGIC1), /* Version number */ SSH_ENCODE_UINT32((SshUInt32) SSH_IKE_EXPORT_VERSION), /* Cookies, initiator, responder */ SSH_ENCODE_DATA(sa->cookies.initiator_cookie, SSH_IKE_COOKIE_LENGTH), SSH_ENCODE_DATA(sa->cookies.responder_cookie, SSH_IKE_COOKIE_LENGTH), /* Local ip, port. */ SSH_ENCODE_UINT32_STR( pm_info->local_ip, ssh_ustrlen(pm_info->local_ip)), SSH_ENCODE_UINT32_STR( pm_info->local_port, ssh_ustrlen(pm_info->local_port)), /* Remote ip, port. */ SSH_ENCODE_UINT32_STR( pm_info->remote_ip, ssh_ustrlen(pm_info->remote_ip)), SSH_ENCODE_UINT32_STR( pm_info->remote_port, ssh_ustrlen(pm_info->remote_port)), /* IKE exchange version. */ SSH_ENCODE_UINT32((SshUInt32) pm_info->major_version), SSH_ENCODE_UINT32((SshUInt32) pm_info->minor_version), /* IKE exchange type. */ SSH_ENCODE_UINT32((SshUInt32) pm_info->exchange_type), /* Was this the initiator for the original exchange? */ SSH_ENCODE_UINT32((SshUInt32) pm_info->this_end_is_initiator), /* Byte count and byte limit. */ SSH_ENCODE_UINT64((SshUInt64) sa->byte_count), SSH_ENCODE_UINT64((SshUInt64) sa->kbyte_limit), /* Created time and laste use time */ SSH_ENCODE_UINT64((SshUInt64) sa->created_time), SSH_ENCODE_UINT64((SshUInt64) sa->last_use_time), /* Encryption, hash, prf algorithm names. */ SSH_ENCODE_UINT32_STR(sa->encryption_algorithm_name, ssh_ustrlen(sa->encryption_algorithm_name)), SSH_ENCODE_UINT32_STR(sa->hash_algorithm_name, ssh_ustrlen(sa->hash_algorithm_name)), SSH_ENCODE_UINT32_STR(sa->prf_algorithm_name, ssh_ustrlen(sa->prf_algorithm_name)), /* Cipher key. */ SSH_ENCODE_UINT32_STR(sa->cipher_key, sa->cipher_key_len), /* Cipher IV. */ SSH_ENCODE_UINT32_STR(sa->cipher_iv, sa->cipher_iv_len), /* Keying material, Diffie-Hellman. */ SSH_ENCODE_UINT32_STR(sa->skeyid.dh, sa->skeyid.dh_size), /* Keying material, SKEYID mac. */ SSH_ENCODE_UINT32_STR(sa->skeyid.skeyid, sa->skeyid.skeyid_size), /* Keying material, SKEYID_d mac. */ SSH_ENCODE_UINT32_STR(sa->skeyid.skeyid_d, sa->skeyid.skeyid_d_size), /* Keying material, SKEYID_a mac. */ SSH_ENCODE_UINT32_STR(sa->skeyid.skeyid_a, sa->skeyid.skeyid_a_size), /* Keying material, SKEYID_e mac. */ SSH_ENCODE_UINT32_STR(sa->skeyid.skeyid_e, sa->skeyid.skeyid_e_size), /* Retry defaults. */ SSH_ENCODE_UINT32(sa->retry_limit), SSH_ENCODE_UINT32(sa->retry_timer), SSH_ENCODE_UINT32(sa->retry_timer_usec), SSH_ENCODE_UINT32(sa->retry_timer_max), SSH_ENCODE_UINT32(sa->retry_timer_max_usec), SSH_ENCODE_UINT32(sa->expire_timer), SSH_ENCODE_UINT32(sa->expire_timer_usec), /* Statistics. */ SSH_ENCODE_UINT32(sa->statistics.packets_in), SSH_ENCODE_UINT32(sa->statistics.packets_out), SSH_ENCODE_UINT32(sa->statistics.octects_in), SSH_ENCODE_UINT32(sa->statistics.octects_out), SSH_ENCODE_UINT32(sa->statistics.created_suites), SSH_ENCODE_UINT32(sa->statistics.deleted_suites), /* IKE SA negotiation information. */ SSH_ENCODE_UINT32((SshUInt32) ike_negotiation->exchange_type), /* This field used to be in negotation structure, now it is in ExchangeData strcuture which is already freed. Put the copy of the value from pm_info here to be compatible with old versions. */ SSH_ENCODE_UINT32((SshUInt32) pm_info->auth_method_type), SSH_ENCODE_UINT32((SshUInt32) 0), /* Private groups as UINT32_STRING. */ SSH_ENCODE_UINT32_STR(ssh_ustr(""), 0), SSH_FORMAT_END); if (item_len == 0) goto error; len += item_len; /* Local id. */ item_len = ssh_ike_sa_export_id(buffer, pm_info->local_id); if (item_len == 0) goto error; len += item_len; /* Remote id. */ item_len = ssh_ike_sa_export_id(buffer, pm_info->remote_id); if (item_len == 0) goto error; len += item_len; item_len = ssh_encode_buffer (buffer, /* Authentication type. */ SSH_ENCODE_UINT32((SshUInt32) pm_info->auth_method_type), SSH_ENCODE_UINT32((SshUInt32) pm_info->auth_method), /* Start and expire times. */ SSH_ENCODE_UINT64((SshUInt64) pm_info->sa_start_time), SSH_ENCODE_UINT64((SshUInt64) pm_info->sa_expire_time), /* None of the policy manager filled data is copied, this include auth_data, auth_data_len, own_auth_data, own_auth_data_len, public_key, number_of_certificates, number_of_allocated_certificates, certificates, certificate_lens, certificate_encodings, policy_manager_data, pm. */ SSH_ENCODE_UINT32((SshUInt32) pm_info->doi), /* Magic number */ SSH_ENCODE_UINT32((SshUInt32) SSH_IKE_EXPORT_MAGIC2), SSH_FORMAT_END); if (item_len == 0) goto error; len += item_len; return len; error: orig_len -= ssh_buffer_len(buffer); if (orig_len != 0) ssh_buffer_consume_end(buffer, orig_len); return 0; }
/* Import given buffer to the IKE Server given in the argument. Returns the IKE SA negotiation or NULL in case of error. The data that was parsed successfully is consumed from the buffer in any case. If there is extra data after the complete packet then it is left to the buffer. */ SshIkeNegotiation ssh_ike_sa_import(SshBuffer buffer, SshIkeServerContext server) { unsigned char initiator_cookie[SSH_IKE_COOKIE_LENGTH]; unsigned char responder_cookie[SSH_IKE_COOKIE_LENGTH]; unsigned char *auc, *buc, *cuc, *duc; SshUInt32 a32, b32, c32, d32; SshUInt64 a64, b64, c64, d64; SshIkePMPhaseI pm_info; SshIkeNegotiation neg; SshIkeSA sa; size_t len; long l; SshADTHandle h; SshCryptoStatus cret; SshTime t; SshUInt16 local_port; sa = NULL; pm_info = NULL; neg = NULL; auc = NULL; buc = NULL; cuc = NULL; duc = NULL; SSH_DEBUG(5, ("Start")); len = ssh_decode_buffer (buffer, /* Magic number */ SSH_DECODE_UINT32(&a32), /* Version number */ SSH_DECODE_UINT32(&b32), /* Cookies, initiator, responder */ SSH_DECODE_DATA(initiator_cookie, SSH_IKE_COOKIE_LENGTH), SSH_DECODE_DATA(responder_cookie, SSH_IKE_COOKIE_LENGTH), SSH_FORMAT_END); if (len == 0) { SSH_DEBUG(3, ("Could not decode magic, version, cookies")); goto error; } if (a32 != SSH_IKE_EXPORT_MAGIC1) { SSH_DEBUG(3, ("Invalid magic 0x%08x vs 0x%08x", (int) a32, SSH_IKE_EXPORT_MAGIC1)); goto error; } if (b32 != SSH_IKE_EXPORT_VERSION) { SSH_DEBUG(3, ("Invalid version 0x%08x vs 0x%08x", (int) b32, SSH_IKE_EXPORT_VERSION)); goto error; } h = ssh_adt_get_handle_to_equal(server->isakmp_context-> isakmp_cookie_mapping, initiator_cookie); if (h != SSH_ADT_INVALID) { SSH_DEBUG(3, ("Duplicate initiator cookie")); goto error; } sa = ike_sa_allocate(server, initiator_cookie, responder_cookie); if (sa == NULL) { SSH_DEBUG(3, ("ike_sa_allocate_half return error")); goto error; } len = ssh_decode_buffer (buffer, /* Local ip, port. */ SSH_DECODE_UINT32_STR(&auc, NULL), SSH_DECODE_UINT32_STR(&buc, NULL), /* Remote ip, port. */ SSH_DECODE_UINT32_STR(&cuc, NULL), SSH_DECODE_UINT32_STR(&duc, NULL), /* IKE exchange version. */ SSH_DECODE_UINT32(&a32), SSH_DECODE_UINT32(&b32), /* IKE exchange type. */ SSH_DECODE_UINT32(&c32), /* Was this the initiator for the original exchange? */ SSH_DECODE_UINT32(&d32), SSH_FORMAT_END); if (len == 0) { SSH_DEBUG(3, ("Could not decode ip, port, version, exchage type, init")); goto error; } if (!ike_init_isakmp_sa(sa, auc, buc, cuc, duc, a32, b32, c32, d32, FALSE)) { SSH_DEBUG(3, ("Could not init isakmp sa")); goto error; } ssh_free(auc); ssh_free(buc); ssh_free(cuc); ssh_free(duc); auc = NULL; buc = NULL; cuc = NULL; duc = NULL; neg = sa->isakmp_negotiation; pm_info = neg->ike_pm_info; /* Initialize */ sa->phase_1_done = 1; neg->notification_state = SSH_IKE_NOTIFICATION_STATE_ALREADY_SENT; ike_free_negotiation_isakmp(neg); /* Set NAT-T status. */ local_port = ssh_uatoi(sa->isakmp_negotiation->ike_pm_info->local_port); if (local_port != server->normal_local_port) sa->use_natt = 1; /* I think we should count this as SA */ server->statistics->current_ike_sas++; server->statistics->total_ike_sas++; if (neg->ike_pm_info->this_end_is_initiator) { server->statistics->current_ike_sas_initiated++; server->statistics->total_ike_sas_initiated++; } else { server->statistics->current_ike_sas_responded++; server->statistics->total_ike_sas_responded++; } len = ssh_decode_buffer (buffer, /* Byte count and byte limit. */ SSH_DECODE_UINT64(&a64), SSH_DECODE_UINT64(&b64), /* Created time and laste use time */ SSH_DECODE_UINT64(&c64), SSH_DECODE_UINT64(&d64), /* Encryption, hash, prf algorithm names. */ SSH_DECODE_UINT32_STR(&auc, NULL), SSH_DECODE_UINT32_STR(&buc, NULL), SSH_DECODE_UINT32_STR(&cuc, NULL), SSH_FORMAT_END); if (len == 0) { SSH_DEBUG(3, ("Could not decode byte count limit, times, alg names")); goto error; } sa->byte_count = (unsigned long) a64; sa->kbyte_limit = (unsigned long) b64; sa->created_time = (SshTime) c64; sa->last_use_time = (SshTime) d64; l = ssh_find_keyword_number(ssh_ike_encryption_algorithms, ssh_csstr(auc)); if (l == -1) { if (ssh_usstrcmp(auc, "cast128-12-cbc") == 0) sa->encryption_algorithm_name = ssh_custr("cast128-12-cbc"); else { SSH_DEBUG(3, ("Unknown cipher %s", auc)); goto error; } } else { sa->encryption_algorithm_name = ssh_custr(ssh_find_keyword_name(ssh_ike_encryption_algorithms, l)); SSH_ASSERT(sa->encryption_algorithm_name != NULL); } l = ssh_find_keyword_number(ssh_ike_hash_algorithms, ssh_csstr(buc)); if (l == -1) { SSH_DEBUG(3, ("Unknown hash %s", buc)); goto error; } else { sa->hash_algorithm_name = ssh_custr(ssh_find_keyword_name(ssh_ike_hash_algorithms, l)); SSH_ASSERT(sa->hash_algorithm_name != NULL); } l = ssh_find_keyword_number(ssh_ike_hmac_prf_algorithms, ssh_csstr(cuc)); if (l == -1) { SSH_DEBUG(3, ("Unknown prf %s", cuc)); goto error; } else { sa->prf_algorithm_name = ssh_custr(ssh_find_keyword_name(ssh_ike_hmac_prf_algorithms, l)); SSH_ASSERT(sa->prf_algorithm_name != NULL); } ssh_free(auc); ssh_free(buc); ssh_free(cuc); ssh_free(duc); auc = NULL; buc = NULL; cuc = NULL; duc = NULL; len = ssh_decode_buffer (buffer, /* Cipher key. */ SSH_DECODE_UINT32_STR(&sa->cipher_key, &sa->cipher_key_len), /* Cipher IV. */ SSH_DECODE_UINT32_STR(&sa->cipher_iv, &sa->cipher_iv_len), SSH_FORMAT_END); if (len == 0) { SSH_DEBUG(3, ("Could not decode cipher key, iv")); goto error; } len = ssh_decode_buffer (buffer, /* Keying material, Diffie-Hellman. */ SSH_DECODE_UINT32_STR(&sa->skeyid.dh, &sa->skeyid.dh_size), /* Keying material, SKEYID mac. */ SSH_DECODE_UINT32_STR(&sa->skeyid.skeyid, &sa->skeyid.skeyid_size), /* Keying material, SKEYID_d mac. */ SSH_DECODE_UINT32_STR(&sa->skeyid.skeyid_d, &sa->skeyid.skeyid_d_size), /* Keying material, SKEYID_a mac. */ SSH_DECODE_UINT32_STR(&sa->skeyid.skeyid_a, &sa->skeyid.skeyid_a_size), /* Keying material, SKEYID_e mac. */ SSH_DECODE_UINT32_STR(&sa->skeyid.skeyid_e, &sa->skeyid.skeyid_e_size), SSH_FORMAT_END); if (len == 0) { SSH_DEBUG(3, ("Could not decode skeyid")); goto error; } sa->skeyid.initialized = TRUE; cret = ssh_mac_allocate(ssh_csstr(sa->prf_algorithm_name), sa->skeyid.skeyid, sa->skeyid.skeyid_size, &sa->skeyid.skeyid_mac); if (cret != SSH_CRYPTO_OK) { SSH_DEBUG(3, ("ssh_mac_allocate failed: %.200s", ssh_crypto_status_message(cret))); goto error; } cret = ssh_mac_allocate(ssh_csstr(sa->prf_algorithm_name), sa->skeyid.skeyid_a, sa->skeyid.skeyid_a_size, &sa->skeyid.skeyid_a_mac); if (cret != SSH_CRYPTO_OK) { SSH_DEBUG(3, ("ssh_mac_allocate failed: %.200s", ssh_crypto_status_message(cret))); goto error; } cret = ssh_mac_allocate(ssh_csstr(sa->prf_algorithm_name), sa->skeyid.skeyid_e, sa->skeyid.skeyid_e_size, &sa->skeyid.skeyid_e_mac); if (cret != SSH_CRYPTO_OK) { SSH_DEBUG(3, ("ssh_mac_allocate failed: %.200s", ssh_crypto_status_message(cret))); goto error; } len = ssh_decode_buffer (buffer, /* Retry defaults. */ SSH_DECODE_UINT32(&sa->retry_limit), SSH_DECODE_UINT32(&sa->retry_timer), SSH_DECODE_UINT32(&sa->retry_timer_usec), SSH_DECODE_UINT32(&sa->retry_timer_max), SSH_DECODE_UINT32(&sa->retry_timer_max_usec), SSH_DECODE_UINT32(&sa->expire_timer), SSH_DECODE_UINT32(&sa->expire_timer_usec), /* Statistics. */ SSH_DECODE_UINT32(&sa->statistics.packets_in), SSH_DECODE_UINT32(&sa->statistics.packets_out), SSH_DECODE_UINT32(&sa->statistics.octects_in), SSH_DECODE_UINT32(&sa->statistics.octects_out), SSH_DECODE_UINT32(&sa->statistics.created_suites), SSH_DECODE_UINT32(&sa->statistics.deleted_suites), SSH_FORMAT_END); if (len == 0) { SSH_DEBUG(3, ("Could not decode retry, expire timers and stats")); goto error; } len = ssh_decode_buffer (buffer, /* IKE SA negotiation information. */ SSH_DECODE_UINT32(&a32), SSH_DECODE_UINT32(&b32), SSH_DECODE_UINT32(&c32), SSH_FORMAT_END); if (len == 0) { SSH_DEBUG(3, ("Could not decode ike sa info and private group cnt")); goto error; } neg->exchange_type = a32; /* The b32 used to be authe_method_type, but as it was duplicate for the value in pm_info, we ignore it now. */ if (c32 != 0) { ssh_warning("Remote end sent packet including private groups. " "This end does not support transferring of them. " "Private groups ignored"); } len = ssh_decode_buffer (buffer, /* Private groups as UINT32_STRING. */ SSH_DECODE_UINT32_STR(NULL, NULL), SSH_FORMAT_END); if (len == 0) { SSH_DEBUG(3, ("Could not decode private groups info")); goto error; } if (!ssh_ike_sa_import_id(buffer, &pm_info->local_id, &pm_info->local_id_txt)) { SSH_DEBUG(3, ("Could not decode local id")); goto error; } if (!ssh_ike_sa_import_id(buffer, &pm_info->remote_id, &pm_info->remote_id_txt)) { SSH_DEBUG(3, ("Could not decode remote id")); goto error; } len = ssh_decode_buffer (buffer, /* Authentication type. */ SSH_DECODE_UINT32(&a32), SSH_DECODE_UINT32(&b32), /* Start and expire times. */ SSH_DECODE_UINT64(&a64), SSH_DECODE_UINT64(&b64), /* None of the policy manager filled data is copied, this include auth_data, auth_data_len, own_auth_data, own_auth_data_len, public_key, number_of_certificates, number_of_allocated_certificates, certificates, certificate_lens, certificate_encodings, policy_manager_data, pm. */ SSH_DECODE_UINT32(&c32), /* Magic number */ SSH_DECODE_UINT32(&d32), SSH_FORMAT_END); if (len == 0) { SSH_DEBUG(3, ("Could not decode pm info and magic2")); goto error; } pm_info->auth_method_type = a32; pm_info->auth_method = b32; pm_info->sa_start_time = (SshTime) a64; pm_info->sa_expire_time = (SshTime) b64; pm_info->doi = c32; if (d32 != SSH_IKE_EXPORT_MAGIC2) { SSH_DEBUG(3, ("Invalid magic2 0x%08x vs 0x%08x", (int) d32, SSH_IKE_EXPORT_MAGIC2)); goto error; } ssh_cancel_timeouts(SSH_ALL_CALLBACKS, neg); /* Insert expire timer allowing the sa to exists for a while (for bootstrap) */ t = ssh_time(); if (t < pm_info->sa_expire_time) t = pm_info->sa_expire_time - t; else t = 0; t = (t < 30) ? 30 : t; ssh_xregister_timeout((SshUInt32) t, 0, ike_call_ike_remove_isakmp_sa, neg); return neg; error: if (sa != NULL) { if (sa->isakmp_negotiation == NULL) { ike_sa_delete(server->isakmp_context, sa); ssh_free(sa); } else ike_delete_negotiation(sa->isakmp_negotiation); } ssh_free(auc); ssh_free(buc); ssh_free(cuc); ssh_free(duc); return NULL; }
void ikev2_fb_sa_handler(SshIkeNegotiation negotiation, SshIkePMPhaseQm pm_info, int number_of_sas, SshIkeIpsecSelectedSA sas, SshIkeIpsecKeymat keymat, void *sa_callback_context) { SshIkev2FbNegotiation neg; neg = SSH_IKEV2_FB_QM_GET_P1_NEGOTIATION(pm_info); if (neg == NULL) return; neg->ike_sa->last_input_stamp = ssh_time(); SSH_DEBUG(SSH_D_LOWOK, ("SA handler entered, IKE SA %p (neg %p)", pm_info->phase_i->policy_manager_data, neg)); if (number_of_sas != 1) { SSH_DEBUG(SSH_D_FAIL, ("Quick-Mode does not result in one bundle")); goto error; } if (neg->ed->callback) { int i, iproto; SshIkev2PayloadTransform *t; SshIkeIpsecSelectedProtocol p; SshIkeIpsecAttributeEncapsulationModeValues encap; /* Assert that `neg->qm_info' is set correctly. */ SSH_ASSERT(neg->qm_info == pm_info); for (i = 0; i < SSH_IKEV2_TRANSFORM_TYPE_MAX; i++) neg->ed->ipsec_ed->ipsec_sa_transforms[i] = &neg->transforms[i]; /* Fill in the selected transforms into ipsec_ed */ t = neg->ed->ipsec_ed->ipsec_sa_transforms; for (iproto = 0; iproto < sas[0].number_of_protocols; iproto++) { p = &sas[0].protocols[iproto]; if (p->protocol_id == SSH_IKE_PROTOCOL_IPSEC_ESP) { t[SSH_IKEV2_TRANSFORM_TYPE_ENCR]->id = ikev2_fb_v1_esp_id_to_v2_id(p->transform_id.generic); if (p->attributes.key_length) t[SSH_IKEV2_TRANSFORM_TYPE_ENCR]->transform_attribute = (0x800e << 16) | p->attributes.key_length; if (p->attributes.auth_algorithm) t[SSH_IKEV2_TRANSFORM_TYPE_INTEG]->id = ikev2_fb_v1_auth_id_to_v2_id(p->attributes.auth_algorithm); else t[SSH_IKEV2_TRANSFORM_TYPE_INTEG] = NULL; } else if (p->protocol_id == SSH_IKE_PROTOCOL_IPSEC_AH) { t[SSH_IKEV2_TRANSFORM_TYPE_INTEG]->id = ikev2_fb_v1_ah_id_to_v2_id(p->transform_id.generic); t[SSH_IKEV2_TRANSFORM_TYPE_ENCR] = NULL; } else if (p->protocol_id == SSH_IKE_PROTOCOL_IPCOMP) { if (p->spi_size_out == 2) { int j; for (j = 0; j < neg->ipcomp_num; j++) { if (neg->ipcomp_algs[j] == p->transform_id.ipcomp) { neg->ipcomp_num = 1; neg->ipcomp_algs[0] = p->transform_id.ipcomp; neg->ipcomp_cpi_out[0] = SSH_GET_16BIT(p->spi_out); break; } } } } if (p->attributes.group_desc) t[SSH_IKEV2_TRANSFORM_TYPE_D_H]->id = p->attributes.group_desc; else t[SSH_IKEV2_TRANSFORM_TYPE_D_H] = NULL; t[SSH_IKEV2_TRANSFORM_TYPE_ESN]->id = (p->attributes.longseq_size) ? SSH_IKEV2_TRANSFORM_ESN_ESN : SSH_IKEV2_TRANSFORM_ESN_NO_ESN; /* For initiator, notify policymanager about transport mode */ encap = p->attributes.encapsulation_mode; if (encap == IPSEC_VALUES_ENCAPSULATION_MODE_TRANSPORT || encap == IPSEC_VALUES_ENCAPSULATION_MODE_UDP_TRANSPORT || encap == IPSEC_VALUES_ENCAPSULATION_MODE_UDP_DRAFT_TRANSPORT) { (void) ikev2_fb_construct_notify(neg, 0, SSH_IKEV2_NOTIFY_USE_TRANSPORT_MODE, TRUE, 0, NULL, 0, NULL); } } if (neg->ipcomp_num > 0) { for (i = 0; i < neg->ipcomp_num; i++) { unsigned char data[3]; SSH_PUT_16BIT(data, neg->ipcomp_cpi_out[i]); data[2] = neg->ipcomp_algs[i]; (void) ikev2_fb_construct_notify(neg, 0, SSH_IKEV2_NOTIFY_IPCOMP_SUPPORTED, TRUE, 0, NULL, sizeof(data), data); } } } /* Set the outbound SPI to the IPSec exchange data */ if (sas->protocols[0].spi_size_out != 4) goto error; neg->ed->ipsec_ed->spi_outbound = SSH_GET_32BIT(sas->protocols[0].spi_out); SSH_DEBUG(SSH_D_LOWOK, ("Outbound SPI %lx", (unsigned long) neg->ed->ipsec_ed->spi_outbound)); if (!ikev2_fb_fill_keymat(neg->ed, negotiation, sas, keymat)) { SSH_DEBUG(SSH_D_FAIL, ("Cannot generate IKEv2 keying material")); goto error; } SSH_IKEV2_FB_V2_CALL(neg, ipsec_sa_install) (neg->server->sad_handle, neg->ed, ikev2_fb_ipsec_sa_install_done, neg); return; error: /* Even in the case of error, we call the IKEv2 SA installation policy call. The key material is cleared to ensure the installation will fail at the policy manager. */ ssh_free(neg->ed->ipsec_ed->ikev1_keymat); neg->ed->ipsec_ed->ikev1_keymat = NULL; neg->ed->ipsec_ed->ikev1_keymat_len = 0; SSH_IKEV2_FB_V2_CALL(neg, ipsec_sa_install) (neg->server->sad_handle, neg->ed, ikev2_fb_ipsec_sa_install_done, neg); }
void ikev2_fb_notify_request_cb(SshIkev2Error error_code, SshIkev2ProtocolIdentifiers protocol_id, unsigned char *spi, size_t spi_size, SshIkev2NotifyMessageType notify_message_type, unsigned char *notification_data, size_t notification_data_size, void *context) { SshIkev2FbNegotiation neg = context; SSH_IKEV2_FB_V2_COMPLETE_CALL(neg); if (notify_message_type == SSH_IKEV2_NOTIFY_USE_TRANSPORT_MODE) { SshUInt32 sa_flags = neg->ike_sa->flags; if (sa_flags & SSH_IKEV2_IKE_SA_FLAGS_NAT_T_FLOAT_DONE) { if (sa_flags & SSH_IKEV2_FB_IKE_NAT_T_IETF_DRAFT) neg->encapsulation = IPSEC_VALUES_ENCAPSULATION_MODE_UDP_DRAFT_TRANSPORT; else /* Use RFC3497 value for RFC3947 and unknown NAT-T methods */ neg->encapsulation = IPSEC_VALUES_ENCAPSULATION_MODE_UDP_TRANSPORT; } else neg->encapsulation = IPSEC_VALUES_ENCAPSULATION_MODE_TRANSPORT; } else if (notify_message_type == SSH_IKEV2_NOTIFY_IPCOMP_SUPPORTED) { neg->ipcomp_cpi_in = SSH_GET_16BIT(notification_data); if (neg->initiator) { if (neg->ipcomp_num < sizeof(neg->ipcomp_algs)) { neg->ipcomp_algs[neg->ipcomp_num] = notification_data[2]; neg->ipcomp_num++; } else { SSH_DEBUG(SSH_D_FAIL, ("Too many IPCOMP mechanisms for proposal")); } } else { memset(neg->ipcomp_algs, 0, sizeof(neg->ipcomp_algs)); neg->ipcomp_selected = TRUE; neg->ipcomp_num = 1; neg->ipcomp_algs[0] = notification_data[2]; } } else if (notify_message_type == SSH_IKEV2_NOTIFY_INITIAL_CONTACT) { neg->initial_contact = 1; } else if (notify_message_type == 0) { SSH_FSM_CONTINUE_AFTER_CALLBACK(neg->sub_thread); } return; }
static void receive_virtual_adapter_attach_cb(SshInterceptor interceptor, SshVirtualAdapterError error, SshInterceptorIfnum adapter_ifnum, unsigned char *adapter_name, SshVirtualAdapterState adapter_state, SshInterceptorVirtualAdapterOp op) { SshInterceptorVirtualAdapter va; /* Is the operation aborted? */ if (op->aborted) { /* The operation was successful but aborted. Let's just destroy the created adapter. */ if (error == SSH_VIRTUAL_ADAPTER_ERROR_OK) ssh_virtual_adapter_detach(interceptor, adapter_ifnum, NULL_FNPTR, NULL); /* Destroy the adapter context */ if (op->detach_cb) (*op->detach_cb)(op->adapter_context); /* Free operation context. */ free_virtual_adapter_op(interceptor, op); return; } if (error == SSH_VIRTUAL_ADAPTER_ERROR_OK) { /* Register that we know this virtual adapter. */ va = ssh_xcalloc(1, sizeof(*va)); va->adapter_ifnum = adapter_ifnum; va->packet_cb = op->packet_cb; va->detach_cb = op->detach_cb; va->adapter_context = op->adapter_context; ssh_mutex_lock(interceptor->mutex); va->next = interceptor->virtual_adapters; interceptor->virtual_adapters = va; ssh_mutex_unlock(interceptor->mutex); } else { /* Destroy the context if not successful */ if (op->detach_cb) (*op->detach_cb)(op->adapter_context); op->adapter_context = NULL; } SSH_DEBUG(SSH_D_NICETOKNOW, ("received attach callback for virtual adapter %d from forwarder, " "error %d", (int) adapter_ifnum, (int) error)); /* Call the completion function. */ if (op->status_cb) (*op->status_cb)((SshVirtualAdapterError) error, (SshInterceptorIfnum) adapter_ifnum, adapter_name, (SshVirtualAdapterState) adapter_state, op->adapter_context, op->context); /* Unregister operation handle and free operation context. */ ssh_operation_unregister(op->handle); free_virtual_adapter_op(interceptor, op); }
static void receive_virtual_adapter_status_cb(SshInterceptor interceptor, const unsigned char *data, size_t len) { SshUInt32 operation_id; SshUInt32 error; SshUInt32 adapter_ifnum; char *adapter_name; SshUInt32 adapter_state; SshInterceptorVirtualAdapterOp op; SshInterceptorVirtualAdapter va; void *adapter_context; if (ssh_decode_array(data, len, SSH_FORMAT_UINT32, &operation_id, SSH_FORMAT_UINT32, &error, SSH_FORMAT_UINT32, &adapter_ifnum, SSH_FORMAT_UINT32_STR_NOCOPY, &adapter_name, NULL, SSH_FORMAT_UINT32, &adapter_state, SSH_FORMAT_END) != len) { SSH_DEBUG_HEXDUMP(SSH_D_ERROR, ("bad virtual adapter status message"), data, len); return; } /* Lookup the pending operation. */ op = lookup_virtual_adapter_op(interceptor, operation_id); if (op == NULL) { SSH_DEBUG(SSH_D_ERROR, ("unknown virtual adapter operation ID %d", (int) operation_id)); return; } /* Handle attach operations separately. */ if (op->attach) { receive_virtual_adapter_attach_cb(interceptor, error, adapter_ifnum, adapter_name, adapter_state, op); return; } /* Is the operation aborted? */ if (op->aborted) { /* Free the operation context. */ free_virtual_adapter_op(interceptor, op); return; } /* Lookup virtual adapter. */ ssh_mutex_lock(interceptor->mutex); for (va = interceptor->virtual_adapters; va; va = va->next) if (va->adapter_ifnum == adapter_ifnum) break; ssh_mutex_unlock(interceptor->mutex); /* Take adapter context from virtual adapter, if it was found. */ if (va == NULL) adapter_context = op->adapter_context; else adapter_context = va->adapter_context; SSH_DEBUG(SSH_D_NICETOKNOW, ("received status callback for virtual adapter %d from forwarder, " "error %d", (int) adapter_ifnum, (int) error)); /* Call the completion function. */ if (op->status_cb) (*op->status_cb)((SshVirtualAdapterError) error, (SshInterceptorIfnum) adapter_ifnum, adapter_name, (SshVirtualAdapterState) adapter_state, adapter_context, op->context); /* Free operation context if there will be no more status callbacks to this operation. */ if (error != SSH_VIRTUAL_ADAPTER_ERROR_OK_MORE) { /* Unregister operation handle and free operation context. */ ssh_operation_unregister(op->handle); free_virtual_adapter_op(interceptor, op); } }
static void receive_virtual_adapter_packet_cb(SshInterceptor interceptor, const unsigned char *data, size_t len) { SshUInt32 flags; SshUInt32 ifnum_in, ifnum_out; SshUInt32 protocol; const unsigned char *packet, *internal; size_t packet_len, internal_len; SshInterceptorVirtualAdapter va; SshInterceptorPacket pp; if (ssh_decode_array(data, len, SSH_FORMAT_UINT32, &flags, SSH_FORMAT_UINT32, &ifnum_in, SSH_FORMAT_UINT32, &ifnum_out, SSH_FORMAT_UINT32, &protocol, SSH_FORMAT_UINT32_STR_NOCOPY, &packet, &packet_len, SSH_FORMAT_UINT32_STR_NOCOPY, &internal, &internal_len, SSH_FORMAT_END) != len) { SSH_DEBUG_HEXDUMP(SSH_D_ERROR, ("bad virtual adapter receive message"), data, len); return; } /* Find the virtual adapter of this receive operation. */ ssh_mutex_lock(interceptor->mutex); for (va = interceptor->virtual_adapters; va; va = va->next) if (va->adapter_ifnum == ifnum_in) break; ssh_mutex_unlock(interceptor->mutex); if (va == NULL) { SSH_DEBUG(SSH_D_ERROR, ("virtual adapter receive for unknown adapter %d", (int) ifnum_in)); return; } if (va->packet_cb == NULL_FNPTR) return; /* Assert that the interface numbers fit into SshInterceptorIfnum. */ SSH_ASSERT(ifnum_in <= SSH_INTERCEPTOR_MAX_IFNUM); SSH_ASSERT(ifnum_out <= SSH_INTERCEPTOR_MAX_IFNUM); /* Allocate a packet object. */ pp = ssh_interceptor_packet_alloc(interceptor, SSH_PACKET_FROMADAPTER, protocol, (SshInterceptorIfnum) ifnum_in, (SshInterceptorIfnum) ifnum_out, packet_len); if (pp == NULL) { SSH_DEBUG(SSH_D_ERROR, ("could not allocate packet for virtual adapter receive")); return; } if (!ssh_interceptor_packet_import_internal_data(pp, internal, internal_len)) { SSH_DEBUG(SSH_D_ERROR, ("import failed")); return; } pp->flags = flags; if (!ssh_interceptor_packet_copyin(pp, 0, packet, packet_len)) { SSH_DEBUG(SSH_D_ERROR, ("copyin failed, dropping packet")); return; } SSH_DEBUG(SSH_D_NICETOKNOW, ("received packet callback for virtual adapter %d from forwarder.", (int) ifnum_in)); /* Pass the packet to the user-supplied packet callback. */ (*va->packet_cb)(interceptor, pp, va->adapter_context); }
void ssh_virtual_adapter_configure(SshInterceptor interceptor, SshInterceptorIfnum adapter_ifnum, SshVirtualAdapterState adapter_state, SshUInt32 num_addresses, SshIpAddr addresses, SshVirtualAdapterParams params, SshVirtualAdapterStatusCB callback, void *context) { SshInterceptorVirtualAdapter va; SshInterceptorVirtualAdapterOp op; SshBufferStruct ip_buffer; unsigned char *param_ptr; size_t param_len; SshUInt32 i; SshVirtualAdapterError error = SSH_VIRTUAL_ADAPTER_ERROR_UNKNOWN_ERROR; SshIpAddrStruct undefined_ip; ssh_buffer_init(&ip_buffer); /* Assert that this virtual adapter exists. */ ssh_mutex_lock(interceptor->mutex); for (va = interceptor->virtual_adapters; va; va = va->next) if (va->adapter_ifnum == adapter_ifnum) break; ssh_mutex_unlock(interceptor->mutex); SSH_ASSERT(va != NULL); /* Encode "clear all addresses" as one undefined address. */ if (num_addresses == 0 && addresses != NULL) { SSH_IP_UNDEFINE(&undefined_ip); addresses = &undefined_ip; num_addresses = 1; } /* Encode IP addresses. */ for (i = 0; i < num_addresses; i++) { if (!ssh_encode_ipaddr_buffer(&ip_buffer, &addresses[i])) { error = SSH_VIRTUAL_ADAPTER_ERROR_ADDRESS_FAILURE; goto error; } } /* Encode params. */ param_ptr = NULL; param_len = 0; if (params) { if (!ssh_virtual_adapter_param_encode(params, ¶m_ptr, ¶m_len)) { error = SSH_VIRTUAL_ADAPTER_ERROR_ADDRESS_FAILURE; goto error; } } /* Initialize an operation handle. */ op = alloc_virtual_adapter_op(interceptor); op->status_cb = callback; op->context = context; SSH_DEBUG(SSH_D_NICETOKNOW, ("sending configure request for virtual adapter %d to forwarder.", (int) adapter_ifnum)); /* Send a message to the kernel forwarder module. */ ssh_usermode_interceptor_send_encode( interceptor, SSH_ENGINE_IPM_FORWARDER_VIRTUAL_ADAPTER_CONFIGURE, SSH_FORMAT_UINT32, op->id, SSH_FORMAT_UINT32, adapter_ifnum, SSH_FORMAT_UINT32, adapter_state, SSH_FORMAT_UINT32, num_addresses, SSH_FORMAT_UINT32_STR, ssh_buffer_ptr(&ip_buffer), ssh_buffer_len(&ip_buffer), SSH_FORMAT_UINT32_STR, param_ptr, param_len, SSH_FORMAT_END); op->handle = ssh_operation_register(virtual_adapter_operation_abort, op); ssh_buffer_uninit(&ip_buffer); ssh_free(param_ptr); return; error: ssh_buffer_uninit(&ip_buffer); ssh_free(param_ptr); (*callback)(error, adapter_ifnum, NULL, SSH_VIRTUAL_ADAPTER_STATE_UNDEFINED, NULL, context); }
int main(int argc, char **argv) { SshExternalKeyTestCtx test_ctx; int i; SshPrivateKey prv_key; SshPublicKey pub_key; SshMPInteger n; parse_arguments(argc, argv); ssh_pk_provider_register(&ssh_pk_if_modn_generator); /* Initialize the event loop and the test context. */ ssh_event_loop_initialize(); ssh_debug_set_level_string(debug_level_string); ssh_global_init(); /* Initialize the crypto library. */ if (ssh_crypto_library_initialize() != SSH_CRYPTO_OK) ssh_fatal("Cannot initialize the crypto library"); test_ctx = ssh_xcalloc(1, sizeof(*test_ctx)); test_ctx->accelerated_encrypts_left = default_accelerated_encrypts; test_ctx->timer = ssh_time_measure_allocate(); SSH_DEBUG(3, ("Reading the test key. Please wait....")); prv_key = get_prv_key("accelerator-test.prv"); if (ssh_private_key_select_scheme(prv_key, SSH_PKF_ENCRYPT, "rsa-none-none", SSH_PKF_END) != SSH_CRYPTO_OK) ssh_fatal("Could not select the scheme for private key"); if (ssh_private_key_derive_public_key(prv_key, &pub_key) != SSH_CRYPTO_OK) { ssh_fatal("Can not derive a public key from a " "stored private key"); } if (ssh_public_key_select_scheme(pub_key, SSH_PKF_ENCRYPT, "rsa-none-none", SSH_PKF_END) != SSH_CRYPTO_OK) ssh_fatal("Could not select the scheme for public key"); n = ssh_mprz_malloc(); /* Get information about the RSA key. E and N are needed for nFast. */ if (ssh_public_key_get_info(pub_key, SSH_PKF_MODULO_N, n, SSH_PKF_END) != SSH_CRYPTO_OK) { return FALSE; } #if 0 n_bytes = (ssh_mprz_get_size(n, 2) + 7) / 8; if (n_bytes == 0 || (n_bytes & 3) != 0) n_bytes += (4 - (n_bytes & 3)); test_ctx->big_buf = ssh_xmalloc(n_bytes); test_ctx->big_buf_len = n_bytes; ssh_mprz_get_buf(test_ctx->big_buf, test_ctx->big_buf_len, n); ssh_mprz_free(n); test_ctx->big_buf_len = 128; test_ctx->big_buf[0] = 1; #else #if 0 n_bytes = ssh_mprz_get_size(n, 8); test_ctx->big_buf = ssh_xmalloc(n_bytes); test_ctx->big_buf_len = n_bytes; ssh_mprz_init(&r); ssh_mprz_rand(&r, n_bytes * 8); ssh_mprz_mod(&r, &r, n); ssh_mprz_get_buf(test_ctx->big_buf, test_ctx->big_buf_len, &r); ssh_mprz_free(n); ssh_mprz_clear(&r); #else test_ctx->big_buf = ssh_xmalloc(129); test_ctx->big_buf_len = 129; memcpy(test_ctx->big_buf, "\x00\x50\xe7\x85\x86\x40\xf8\x9b" "\xb8\xeb\x19\x64\xd8\x51\x33\xd7" "\x4f\xac\x32\x5d\x03\x66\x3d\x0c" "\xbe\xfd\x40\x29\x82\xb7\x61\x09" "\x15\x37\x4f\xe1\xd0\x57\xb0\x6d" "\x16\x49\x73\x25\x20\x3d\xa8\xfa" "\xf6\xb4\x72\xec\x75\xc8\x42\xc7" "\x99\x64\x63\x23\x29\xe0\x65\xa1" "\x2a\xc2\xb7\xf1\x5b\xb4\x9b\x30" "\xdb\xc7\x22\xb9\xf9\xde\xb5\x09" "\xb5\xe0\x0a\xca\xc5\xf9\xaf\x8f" "\x54\xf2\x9a\x06\x2b\xc1\xc2\x65" "\x87\xb3\xd5\xec\xd3\x8a\x2f\xa7" "\x5f\x69\x34\xe7\x7f\xeb\xaf\x56" "\x3c\x3d\x71\x3f\x73\xba\x8b\xa7" "\xd3\xe5\x6d\x98\xc8\x01\x6b\x18" "\x14", 129); #endif #endif test_ctx->pub_key = pub_key; test_ctx->prv_key = prv_key; test_ek_add(test_ctx); #ifndef WIN32 ssh_register_signal(SIGUSR1, test_signal_handler, test_ctx); #endif ssh_event_loop_run(); /* Uninitialize. */ for (i = 0; i < test_ctx->num_prv_keys; i++) ssh_private_key_free(test_ctx->prv_keys[i]); for (i = 0; i < test_ctx->num_pub_keys; i++) ssh_public_key_free(test_ctx->pub_keys[i]); ssh_xfree(test_ctx->prv_keys); ssh_xfree(test_ctx->pub_keys); ssh_xfree(test_ctx); return 0; }
SshRadiusUrlStatus ssh_radius_url_create_request(SshOperationHandle *result, SshRadiusClientRequestCB cb, void *ctx, ...) { SshRadiusUrlRequest url_req; SshRadiusAvpType avp_type; va_list ap; unsigned char *cp; size_t idx,len; SshRadiusUrlStatus url_status; SSH_DEBUG(SSH_D_HIGHSTART,("creating RADIUS URL request")); *result = NULL; url_req = ssh_calloc(1, sizeof(*url_req)); if (url_req == NULL) { SSH_DEBUG(SSH_D_FAIL,("Out of memory")); return SSH_RADIUS_URL_OUT_OF_MEMORY; } url_req->cb = cb; /* Scan for memory needs */ va_start(ap, ctx); while ((cp = va_arg(ap, unsigned char*)) != NULL) url_req->nurls++; va_end(ap); url_req->url = ssh_calloc(1,sizeof(unsigned char*)*url_req->nurls); ssh_radius_url_init_avpset(&url_req->avp_set, NULL); if (url_req->url == NULL) { SSH_DEBUG(SSH_D_FAIL,("Out of memory")); ssh_radius_url_destroy_request(url_req); return SSH_RADIUS_URL_OUT_OF_MEMORY; } /* Grab a copy of the user parameters */ va_start(ap,ctx); for (idx = 0; idx < url_req->nurls; idx++) { cp = va_arg(ap,unsigned char *); SSH_ASSERT(cp != NULL); url_req->url[idx] = ssh_strdup(cp); if (url_req->url[idx] == NULL) { SSH_DEBUG(SSH_D_FAIL,("Out of memory")); ssh_radius_url_destroy_request(url_req); return SSH_RADIUS_URL_OUT_OF_MEMORY; } url_status = ssh_radius_url_isok(cp); if (url_status != SSH_RADIUS_URL_STATUS_SUCCESS) { SSH_DEBUG(SSH_D_FAIL,("error parsing URL %s",cp)); ssh_radius_url_destroy_request(url_req); return url_status; } } while ((cp = va_arg(ap, unsigned char*)) != NULL) { len = va_arg(ap, size_t); avp_type = va_arg(ap, SshRadiusAvpType); SSH_ASSERT(cp != NULL); if (ssh_radius_url_set_avpset_avp(&url_req->avp_set, avp_type, cp, (SshUInt8)len) == FALSE) { SSH_DEBUG(SSH_D_FAIL,("Out of memory")); ssh_radius_url_destroy_request(url_req); return SSH_RADIUS_URL_OUT_OF_MEMORY; } } va_end(ap); url_req->req = NULL; url_req->s_info = NULL; url_req->url_idx = 0; url_req->ctx = ctx; url_req->url_handle = ssh_operation_register(ssh_radius_url_request_abort, url_req); if (url_req->url_handle == NULL) { SSH_DEBUG(SSH_D_FAIL,("Failed to register operation handle")); ssh_radius_url_destroy_request(url_req); return SSH_RADIUS_URL_OUT_OF_MEMORY; } url_status = ssh_radius_url_do_next(url_req); if (url_status != SSH_RADIUS_URL_STATUS_SUCCESS) { ssh_radius_url_destroy_request(url_req); return url_status; } *result = url_req->url_handle; return SSH_RADIUS_URL_STATUS_SUCCESS; }
void ikev2_fb_spd_select_qm_sa_cb(SshIkev2Error error_code, int ikev2_proposal_index, SshIkev2PayloadTransform selected_transforms[SSH_IKEV2_TRANSFORM_TYPE_MAX], void *context) { SshIkev2FbNegotiation neg = context; SshIkeIpsecSelectedSAIndexes selected = NULL; SshIkePayloadSA sa; int ikev1_proposal_index, ikev1_ipsec_transform_index; int ikev1_ipcomp_transform_index, i, iproto; SSH_IKEV2_FB_V2_COMPLETE_CALL(neg); sa = &neg->sa_table_in[0]->pl.sa; if (error_code != SSH_IKEV2_ERROR_OK) { SSH_DEBUG(SSH_D_FAIL, ("IKEv2 SA select failed with error %s", ssh_ikev2_error_to_string(error_code))); goto error; } /* Check if ISAKMP library has freed the qm negotiation. */ if (neg->qm_info == NULL) { SSH_DEBUG(SSH_D_FAIL, ("QM negotiation has disappeared")); neg->ike_error = SSH_IKEV2_ERROR_INVALID_ARGUMENT; goto error; } if (selected_transforms == NULL) { SSH_DEBUG(SSH_D_FAIL, ("No IPSec SA transforms selected")); goto error; } /* Store information on the selected SA to the IPSec exchange data. */ for (i = 0; i < SSH_IKEV2_TRANSFORM_TYPE_MAX; i++) { neg->ed->ipsec_ed->ipsec_sa_transforms[i] = selected_transforms[i]; } neg->ed->ipsec_ed->ipsec_sa_protocol = neg->sav2->protocol_id[ikev2_proposal_index]; /* Set the inbound SPI to the IPSec exchange data */ neg->ed->ipsec_ed->spi_inbound = neg->inbound_spi; SSH_DEBUG(SSH_D_LOWOK, ("Inbound SPI %lx", (unsigned long) neg->inbound_spi)); SSH_ASSERT(neg->number_of_sas_in == 1); selected = ssh_calloc(neg->number_of_sas_in, sizeof(*selected)); if (selected == NULL) goto error; /* Check to see which proposal and ESP/AH/IPComp transform index was selected. */ if (!ikev2_fb_select_ipsec_transform_index(selected_transforms, neg->qm_info->negotiation, sa, neg->ipcomp_proposals, neg->ipcomp_algs[0], &ikev1_proposal_index, &ikev1_ipsec_transform_index, &ikev1_ipcomp_transform_index)) { error: SSH_DEBUG(SSH_D_FAIL, ("SA selection failed, no matching proposal (neg %p)", neg)); ikev2_fb_free_sa_indexes(selected, neg->number_of_sas_in); neg->selected = NULL; SSH_FSM_CONTINUE_AFTER_CALLBACK(neg->sub_thread); return; } selected[0].proposal_index = ikev1_proposal_index; SSH_DEBUG(SSH_D_LOWOK, ("Selected proposal indices are v2=%d, v1=%d num protocols is %d", ikev2_proposal_index, ikev1_proposal_index, sa->proposals[ikev1_proposal_index].number_of_protocols)); selected[0].number_of_protocols = sa->proposals[ikev1_proposal_index].number_of_protocols; selected[0].transform_indexes = ssh_calloc(selected[0].number_of_protocols, sizeof(int)); selected[0].spi_sizes = ssh_calloc(selected[0].number_of_protocols, sizeof(size_t)); selected[0].spis = ssh_calloc(selected[0].number_of_protocols, sizeof(unsigned char *)); if (selected[0].transform_indexes == NULL || selected[0].spi_sizes == NULL || selected[0].spis == NULL) goto error; for (iproto = 0; iproto < selected[0].number_of_protocols; iproto++) { SshIkePayloadPProtocol proto = &sa->proposals[ikev1_proposal_index].protocols[iproto]; if ((selected->spis[iproto] = ssh_malloc(4)) == NULL) goto error; switch (proto->protocol_id) { case SSH_IKE_PROTOCOL_IPCOMP: selected->spi_sizes[iproto] = 2; SSH_PUT_16BIT(selected->spis[iproto], neg->ipcomp_cpi_in); selected[0].transform_indexes[iproto] = ikev1_ipcomp_transform_index; break; default: selected->spi_sizes[iproto] = 4; SSH_PUT_32BIT(selected->spis[iproto], neg->inbound_spi); /* Check the proposed lifetimes against that of our policy to see whether we should send a responder lifetime notification */ if (ikev2_fb_check_ipsec_responder_lifetimes(neg->ed, neg->sa_life_seconds, neg->sa_life_kbytes)) { /* Let's send a responder lifetime notify. */ SSH_DEBUG(SSH_D_NICETOKNOW, ("Sending a responder lifetime notification: " "life_sec=%lu, life_kb=%lu", neg->ed->ipsec_ed->sa_life_seconds, neg->ed->ipsec_ed->sa_life_kbytes)); selected[0].expire_secs = neg->ed->ipsec_ed->sa_life_seconds; selected[0].expire_kb = neg->ed->ipsec_ed->sa_life_kbytes; } selected[0].transform_indexes[iproto] = ikev1_ipsec_transform_index; } } neg->selected = selected; SSH_FSM_CONTINUE_AFTER_CALLBACK(neg->sub_thread); return; }
/* Expore identity payload to buffer. Buffer is NOT cleared, before the export. Returns size of the data added to the buffer, or 0 in case of error. In case of error the data added to the buffer is removed. */ size_t ssh_ike_sa_export_id(SshBuffer buffer, SshIkePayloadID id) { size_t orig_len; size_t item_len; size_t len; SSH_DEBUG(5, ("Start")); orig_len = ssh_buffer_len(buffer); len = 0; if (id == NULL) { item_len = ssh_encode_buffer (buffer, SSH_ENCODE_UINT32((SshUInt32) 0), SSH_FORMAT_END); if (item_len == 0) goto error; len += item_len; return len; } item_len = ssh_encode_buffer (buffer, SSH_ENCODE_UINT32((SshUInt32) id->id_type), SSH_ENCODE_UINT32((SshUInt32) id->protocol_id), SSH_ENCODE_UINT32((SshUInt32) id->port_number), SSH_ENCODE_UINT32((SshUInt32) id->port_range_end), SSH_FORMAT_END); if (item_len == 0) goto error; len += item_len; switch (id->id_type) { case IPSEC_ID_IPV4_ADDR: item_len = ssh_encode_buffer (buffer, SSH_ENCODE_DATA(id->identification.ipv4_addr, 4), SSH_FORMAT_END); break; case IPSEC_ID_FQDN: item_len = ssh_encode_buffer (buffer, SSH_ENCODE_UINT32_STR(id->identification.fqdn, id->identification_len), SSH_FORMAT_END); break; case IPSEC_ID_USER_FQDN: item_len = ssh_encode_buffer (buffer, SSH_ENCODE_UINT32_STR(id->identification.user_fqdn, id->identification_len), SSH_FORMAT_END); break; case IPSEC_ID_IPV4_ADDR_SUBNET: item_len = ssh_encode_buffer (buffer, SSH_ENCODE_DATA(id->identification.ipv4_addr_subnet, 4), SSH_ENCODE_DATA(id->identification.ipv4_addr_netmask, 4), SSH_FORMAT_END); break; case IPSEC_ID_IPV6_ADDR: item_len = ssh_encode_buffer (buffer, SSH_ENCODE_DATA(id->identification.ipv6_addr, 16), SSH_FORMAT_END); break; case IPSEC_ID_IPV6_ADDR_SUBNET: item_len = ssh_encode_buffer (buffer, SSH_ENCODE_DATA(id->identification.ipv6_addr_subnet, 16), SSH_ENCODE_DATA(id->identification.ipv6_addr_netmask, 16), SSH_FORMAT_END); break; case IPSEC_ID_IPV4_ADDR_RANGE: item_len = ssh_encode_buffer (buffer, SSH_ENCODE_DATA(id->identification.ipv4_addr_range1, 4), SSH_ENCODE_DATA(id->identification.ipv4_addr_range2, 4), SSH_FORMAT_END); break; case IPSEC_ID_IPV6_ADDR_RANGE: item_len = ssh_encode_buffer (buffer, SSH_ENCODE_DATA(id->identification.ipv6_addr_range1, 16), SSH_ENCODE_DATA(id->identification.ipv6_addr_range2, 16), SSH_FORMAT_END); break; case IPSEC_ID_DER_ASN1_DN: case IPSEC_ID_DER_ASN1_GN: item_len = ssh_encode_buffer (buffer, SSH_ENCODE_UINT32_STR(id->identification.asn1_data, id->identification_len), SSH_FORMAT_END); break; case IPSEC_ID_KEY_ID: item_len = ssh_encode_buffer (buffer, SSH_ENCODE_UINT32_STR(id->identification.key_id, id->identification_len), SSH_FORMAT_END); break; #ifdef SSHDIST_IKE_ID_LIST case IPSEC_ID_LIST: { int cnt; item_len = ssh_encode_buffer(buffer, SSH_ENCODE_UINT32( (SshUInt32) id->identification. id_list_number_of_items), SSH_FORMAT_END); if (item_len == 0) goto error; len += item_len; for (cnt = 0; cnt < id->identification.id_list_number_of_items; cnt++) { item_len = ssh_ike_sa_export_id(buffer, &(id->identification.id_list_items[cnt])); if (item_len == 0) goto error; len += item_len; } break; } #endif /* SSHDIST_IKE_ID_LIST */ } if (item_len == 0) goto error; len += item_len; return len; error: orig_len -= ssh_buffer_len(buffer); if (orig_len != 0) ssh_buffer_consume_end(buffer, orig_len); return 0; }
void ikev2_fb_new_connection_phase_qm(SshIkePMPhaseQm pm_info, SshPolicyNewConnectionCB callback_in, void *callback_context_in) { SshIkev2Fb fb = (SshIkev2Fb) pm_info->pm->upper_context; SshIkeServerContext ike_server; SshIkev2FbNegotiation neg; SshIkev2Sa ike_sa; SSH_ASSERT(pm_info->phase_i != NULL); SSH_ASSERT(pm_info->phase_i->policy_manager_data != NULL); ike_sa = (SshIkev2Sa) pm_info->phase_i->policy_manager_data; /* Allocate and init context for this negotiation. */ if ((neg = ikev2_fallback_negotiation_alloc(fb)) == NULL) { SSH_DEBUG(SSH_D_FAIL, ("Out of negotation contexts.")); (*callback_in)(FALSE, SSH_IKE_FLAGS_USE_DEFAULTS, -1, -1, -1, -1, -1, -1, -1, callback_context_in); return; } /* Take a reference to allocated `neg' and set it to `pm_info->policy_manager_data'. */ ikev2_fb_phase_qm_set_pm_data(pm_info, neg); /* Save `neg->qm_info' here for responder negotiations. */ SSH_ASSERT(neg->qm_info == NULL); neg->qm_info = pm_info; /* Lookup the server object used in the negotiation. */ ike_server = ssh_ike_get_server_by_negotiation(pm_info->negotiation); SSH_ASSERT(ike_server != NULL); neg->server = (SshIkev2Server)ike_server; neg->ike_sa = ike_sa; ssh_ikev2_ike_sa_take_ref(neg->ike_sa); neg->ike_sa->last_input_stamp = ssh_time(); if ((neg->ed = ikev2_allocate_exchange_data(neg->ike_sa)) == NULL) goto error; neg->ed->state = SSH_IKEV2_STATE_CREATE_CHILD; if (ikev2_allocate_exchange_data_ipsec(neg->ed) != SSH_IKEV2_ERROR_OK) goto error; SSH_DEBUG(SSH_D_NICETOKNOW, ("Accepting new Quick-Mode negotiation: " "local=%s:%s, remote=%s:%s (neg %p)", pm_info->local_ip, pm_info->local_port, pm_info->remote_ip, pm_info->remote_port, neg)); /* Start the main thread controlling this negotiation */ ssh_fsm_thread_init(fb->fsm, neg->thread, ikev2_fb_qm_negotiation_wait_sa_installation, NULL_FNPTR, ikev2_fb_qm_negotiation_destructor, neg); (*callback_in)(TRUE, SSH_IKE_FLAGS_USE_DEFAULTS, -1, -1, -1, -1, -1, -1, -1, callback_context_in); return; error: SSH_DEBUG(SSH_D_LOWOK, ("New connection failed (neg %p)", neg)); SSH_ASSERT(neg != NULL); /* Release reference to `neg' from `pm_info->policy_manager_data'. */ ikev2_fb_phase_qm_clear_pm_data(pm_info, neg); /* Free negotiation. */ ikev2_fallback_negotiation_free(fb, neg); (*callback_in)(FALSE, SSH_IKE_FLAGS_USE_DEFAULTS, -1, -1, -1, -1, -1, -1, -1, callback_context_in); return; }
/* Import id from the buffer and store newly allocated id to the id pointer, freeing the old id if such was stored there. If the id_txt pointer is given then it is used to store the textual format of the id. If that pointer contained old id string it is freed before the new string stored there. Returns TRUE if successful and FALSE otherwise. In case of error the buffer is left unspecified state (i.e part of it might be consumed). */ Boolean ssh_ike_sa_import_id(SshBuffer buffer, SshIkePayloadID *id, char **id_txt) { SshUInt32 a32, b32, c32; SshIkePayloadID newp = NULL; char newp_txt[255]; size_t ret = 0; SSH_DEBUG(5, ("Start")); if (ssh_decode_buffer (buffer, SSH_DECODE_UINT32(&a32), SSH_FORMAT_END) == 0) goto error; if (a32 == 0) { if (id) { ssh_ike_id_free(*id); *id = NULL; } if (id_txt) { ssh_free(*id_txt); *id_txt = ssh_strdup("No Id"); if (*id == NULL) return FALSE; } return TRUE; } newp = ssh_malloc(sizeof(*newp)); if (newp == NULL) return FALSE; newp->raw_id_packet = NULL; newp->id_type = a32; if (ssh_decode_buffer (buffer, SSH_DECODE_UINT32(&a32), SSH_DECODE_UINT32(&b32), SSH_DECODE_UINT32(&c32), SSH_FORMAT_END) == 0) goto error; newp->protocol_id = a32; newp->port_number = b32; newp->port_range_end = c32; switch (newp->id_type) { case IPSEC_ID_IPV4_ADDR: ret = ssh_decode_buffer (buffer, SSH_DECODE_DATA(newp->identification.ipv4_addr, 4), SSH_FORMAT_END); newp->identification_len = 4; break; case IPSEC_ID_FQDN: ret = ssh_decode_buffer (buffer, SSH_DECODE_UINT32_STR(&newp->identification.fqdn, &newp->identification_len), SSH_FORMAT_END); break; case IPSEC_ID_USER_FQDN: ret = ssh_decode_buffer (buffer, SSH_DECODE_UINT32_STR(&newp->identification.user_fqdn, &newp->identification_len), SSH_FORMAT_END); break; case IPSEC_ID_IPV4_ADDR_SUBNET: ret = ssh_decode_buffer (buffer, SSH_DECODE_DATA(newp->identification.ipv4_addr_subnet, 4), SSH_DECODE_DATA(newp->identification.ipv4_addr_netmask, 4), SSH_FORMAT_END); newp->identification_len = 8; break; case IPSEC_ID_IPV6_ADDR: ret = ssh_decode_buffer (buffer, SSH_DECODE_DATA(newp->identification.ipv6_addr, 16), SSH_FORMAT_END); newp->identification_len = 16; break; case IPSEC_ID_IPV6_ADDR_SUBNET: ret = ssh_decode_buffer (buffer, SSH_DECODE_DATA(newp->identification.ipv6_addr_subnet, 16), SSH_DECODE_DATA(newp->identification.ipv6_addr_netmask, 16), SSH_FORMAT_END); newp->identification_len = 32; break; case IPSEC_ID_IPV4_ADDR_RANGE: ret = ssh_decode_buffer (buffer, SSH_DECODE_DATA(newp->identification.ipv4_addr_range1, 4), SSH_DECODE_DATA(newp->identification.ipv4_addr_range2, 4), SSH_FORMAT_END); newp->identification_len = 8; break; case IPSEC_ID_IPV6_ADDR_RANGE: ret = ssh_decode_buffer (buffer, SSH_DECODE_DATA(newp->identification.ipv6_addr_range1, 16), SSH_DECODE_DATA(newp->identification.ipv6_addr_range2, 16), SSH_FORMAT_END); newp->identification_len = 32; break; case IPSEC_ID_DER_ASN1_DN: case IPSEC_ID_DER_ASN1_GN: ret = ssh_decode_buffer (buffer, SSH_DECODE_UINT32_STR(&newp->identification.asn1_data, &newp->identification_len), SSH_FORMAT_END); break; case IPSEC_ID_KEY_ID: ret = ssh_decode_buffer (buffer, SSH_DECODE_UINT32_STR(&newp->identification.key_id, &newp->identification_len), SSH_FORMAT_END); break; #ifdef SSHDIST_IKE_ID_LIST case IPSEC_ID_LIST: { int cnt; SshIkePayloadID itemp = NULL; newp->identification_len = 0; ret = ssh_decode_buffer (buffer, SSH_DECODE_UINT32((SshUInt32 *)&newp->identification. id_list_number_of_items), SSH_FORMAT_END); if (ret == 0) goto error; newp->identification.id_list_items = ssh_calloc(newp->identification.id_list_number_of_items, sizeof(newp->identification.id_list_items[0])); if (newp->identification.id_list_items == NULL) goto error; for (cnt = 0; cnt < newp->identification.id_list_number_of_items; cnt++) { if (!ssh_ike_sa_import_id(buffer, &itemp, NULL)) goto error; newp->identification.id_list_items[cnt] = *itemp; ssh_free(itemp); itemp = NULL; } break; } #endif /* SSHDIST_IKE_ID_LIST */ } if (ret == 0) goto error; if (id_txt) { ssh_free(*id_txt); ssh_ike_id_to_string(newp_txt, sizeof(newp_txt), newp); *id_txt = ssh_strdup(newp_txt); if (*id_txt == NULL) goto error; } if (id) { ssh_ike_id_free(*id); *id = newp; } else { ssh_ike_id_free(newp); } return TRUE; error: if (newp != NULL) ssh_ike_id_free(newp); return FALSE; }
void ikev2_fb_qm_select_sa(SshIkePMPhaseQm pm_info, SshIkeNegotiation negotiation, int number_of_sas_in, SshIkePayload *sa_table_in, SshPolicyQmSACB callback_in, void *callback_context_in) { SshIkev2Fb fb = (SshIkev2Fb) pm_info->pm->upper_context; SshIkev2FbNegotiation neg; neg = SSH_IKEV2_FB_QM_GET_P1_NEGOTIATION(pm_info); if (neg == NULL || neg->ike_error != SSH_IKEV2_ERROR_OK) { goto error; } SSH_DEBUG(SSH_D_LOWOK, ("Select QM SA policy call entered, IKE SA %p (neg %p)", pm_info->phase_i->policy_manager_data, neg)); /* Set the proposed traffic selectors to the IPsec exchange data. */ if (pm_info->local_i_id) { neg->ed->ipsec_ed->ts_local = ikev2_fb_tsv1_to_tsv2(neg->server->sad_handle, pm_info->local_i_id); } /* Remote did not send any proxy IDs, default to local IP (RFC2409, 5.5) */ else { neg->ed->ipsec_ed->ts_local = ssh_ikev2_ts_allocate(neg->server->sad_handle); if (neg->ed->ipsec_ed->ts_local != NULL) { SshIpAddrStruct addr; SSH_VERIFY(ssh_ipaddr_parse(&addr, pm_info->local_ip)); SSH_VERIFY(ssh_ikev2_ts_item_add(neg->ed->ipsec_ed->ts_local, 0, &addr, &addr, 0, 0xffff) == SSH_IKEV2_ERROR_OK); } } /* Replace FQDN remote ID with the IKE peer's remote IP if NAT-T is used */ if (neg->ike_sa->flags & SSH_IKEV2_IKE_SA_FLAGS_NAT_T_FLOAT_DONE && pm_info->remote_i_id && pm_info->remote_i_id->id_type == IPSEC_ID_FQDN) { neg->ed->ipsec_ed->ts_remote = ssh_ikev2_ts_allocate(neg->server->sad_handle); if (neg->ed->ipsec_ed->ts_remote) { SshIpAddrStruct addr; SshUInt16 s_port, e_port; SSH_VERIFY(ssh_ipaddr_parse(&addr, pm_info->remote_ip)); s_port = pm_info->remote_i_id->port_number; if (pm_info->remote_i_id->port_number != 0) e_port = pm_info->remote_i_id->port_number; else e_port = 0xffff; SSH_VERIFY(ssh_ikev2_ts_item_add(neg->ed->ipsec_ed->ts_remote, pm_info->remote_i_id->protocol_id, &addr, &addr, s_port, e_port) == SSH_IKEV2_ERROR_OK); } } else if (pm_info->remote_i_id) { neg->ed->ipsec_ed->ts_remote = ikev2_fb_tsv1_to_tsv2(neg->server->sad_handle,pm_info->remote_i_id); } /* Remote did not send any proxy IDs, default to remote IP (RFC2409, 5.5) */ else { neg->ed->ipsec_ed->ts_remote = ssh_ikev2_ts_allocate(neg->server->sad_handle); if (neg->ed->ipsec_ed->ts_remote != NULL) { SshIpAddrStruct addr; SSH_VERIFY(ssh_ipaddr_parse(&addr, pm_info->remote_ip)); SSH_VERIFY(ssh_ikev2_ts_item_add(neg->ed->ipsec_ed->ts_remote, 0, &addr, &addr, 0, 0xffff) == SSH_IKEV2_ERROR_OK); } } if (neg->ed->ipsec_ed->ts_local == NULL || neg->ed->ipsec_ed->ts_remote == NULL) { (*callback_in)(NULL, callback_context_in); return; } ssh_ikev2_ts_take_ref(neg->server->sad_handle, neg->ed->ipsec_ed->ts_local); ssh_ikev2_ts_take_ref(neg->server->sad_handle, neg->ed->ipsec_ed->ts_remote); /* This is a responder negotiation to ts_r is the local traffic selector and ts_i is the remote traffic selector. */ neg->ed->ipsec_ed->ts_r = neg->ed->ipsec_ed->ts_local; neg->ed->ipsec_ed->ts_i = neg->ed->ipsec_ed->ts_remote; /* Store the SA proposals */ neg->number_of_sas_in = number_of_sas_in; neg->sa_table_in = sa_table_in; /* We only support proposals consisting of one SA. */ if (neg->number_of_sas_in != 1) { SSH_DEBUG(SSH_D_FAIL, ("Multiple SA's not supported")); goto error; } /* Store the completion callback and its context. */ neg->callbacks.u.qm_sa = callback_in; neg->callbacks.callback_context = callback_context_in; /* First extract the proposals that do not contain IPcomp as a protocol */ neg->ipcomp_proposals = FALSE; /* Take a reference to fallback negotiation structure for the sub thread. It will be freed in the sub thread destructor. */ IKEV2_FB_NEG_TAKE_REF(neg); ssh_fsm_thread_init(fb->fsm, neg->sub_thread, ikev2_fb_st_select_qm_sa_start, NULL_FNPTR, ikev2_fb_select_qm_sa_sub_thread_destructor, neg); return; error: (*callback_in)(NULL, callback_context_in); return; }
SshCMStatus ssh_cm_add_crl_with_bindings(SshCMCrl crl, SshCertDBKey *bindings) { SshCertDBEntry *entry; SshCMContext cm = crl->cm; SSH_DEBUG(5, ("CRL add to local database/memory cache.")); if (crl == NULL || cm->db == NULL) { ssh_certdb_key_free(bindings); return SSH_CM_STATUS_FAILURE; } if (cm->config->local_db_writable == FALSE) { ssh_certdb_key_free(bindings); return SSH_CM_STATUS_FAILURE; } /* Allocate a new entry. */ if (ssh_certdb_alloc_entry(cm->db, SSH_CM_DATA_TYPE_CRL, crl, &entry) != SSH_CDBET_OK) { ssh_certdb_key_free(bindings); return SSH_CM_STATUS_COULD_NOT_ALLOCATE; } SSH_DEBUG(SSH_D_MIDOK, ("Explicit crl: %@", ssh_cm_render_crl, crl->crl)); /* Check for collision in the database. Be a optimist anyway... */ if (ssh_cm_crl_check_db_collision(cm, crl, &entry->names)) { unsigned char digest[SSH_MAX_HASH_DIGEST_LENGTH]; size_t length; SshHash hash; SshCertDBEntryList *found; SshCertDBEntryListNode list; SshCMCrl old_crl; /* First fetch colliding old CRL from local cache, timestamp it and clean possible SSH_CM_CRL_FLAG_SKIP-flag */ if (ssh_hash_allocate(SSH_CM_HASH_ALGORITHM, &hash) != SSH_CRYPTO_OK) { SSH_DEBUG(SSH_D_ERROR, ("Can't allocate %s", SSH_CM_HASH_ALGORITHM)); ssh_certdb_release_entry(cm->db, entry); ssh_certdb_key_free(bindings); return SSH_CM_STATUS_COULD_NOT_ALLOCATE; } ssh_hash_update(hash, crl->ber, crl->ber_length); ssh_hash_final(hash, digest); length = ssh_hash_digest_length(ssh_hash_name(hash)); ssh_hash_free(hash); if (length > 8) length = 8; /* Get old CRL from the database. */ if ((ssh_certdb_find(cm->db, SSH_CM_DATA_TYPE_CRL, SSH_CM_KEY_TYPE_BER_HASH, digest, length, &found) == SSH_CDBET_OK) && found->head) { list = found->head; old_crl = list->entry->context; ssh_ber_time_set_from_unix_time(&old_crl->fetch_time, (*cm->config->time_func) (cm->config->time_context)); old_crl->status_flags &= ~SSH_CM_CRL_FLAG_SKIP; SSH_DEBUG(SSH_D_MIDOK, ("CRL exists already in the database, " "updated CRL fetch-time.")); } else { SSH_DEBUG(SSH_D_FAIL, ("CRL exists already in the database, " "could not update CRL fetch-time.")); } ssh_certdb_entry_list_free_all(cm->db, found); /* Prevent database from freeing the CRL */ entry->context = NULL; /* Free the entry allocated. */ ssh_certdb_release_entry(cm->db, entry); ssh_certdb_key_free(bindings); return SSH_CM_STATUS_ALREADY_EXISTS; } /* Initialize the entry. */ crl->entry = entry; if (!ssh_cm_key_set_from_crl(&entry->names, crl)) { /* Prevent database from freeing the CRL */ entry->context = NULL; ssh_certdb_release_entry(cm->db, entry); ssh_certdb_key_free(bindings); return SSH_CM_STATUS_COULD_NOT_ALLOCATE; } if (bindings) ssh_certdb_entry_add_keys(cm->db, entry, bindings); /* Add to the database. */ if (ssh_certdb_add(cm->db, entry) != SSH_CDBET_OK) { /* Prevent database from freeing the CRL */ entry->context = NULL; ssh_certdb_release_entry(cm->db, entry); SSH_DEBUG(4, ("Local database/memory cache denies the addition.")); return SSH_CM_STATUS_COULD_NOT_ALLOCATE; } /* Record CRL addition time */ ssh_ber_time_set_from_unix_time(&crl->fetch_time, (*cm->config->time_func) (cm->config->time_context)); ssh_certdb_release_entry(cm->db, entry); return SSH_CM_STATUS_OK; }
void ikev2_fb_phase_qm_notification(SshIkePMPhaseQm pm_info, SshIkeProtocolIdentifiers proto, unsigned char *spi, size_t spi_size, SshIkeNotifyMessageType type, unsigned char *data, size_t data_size) { SshIkev2FbNegotiation neg; char buffer[64]; neg = SSH_IKEV2_FB_QM_GET_P1_NEGOTIATION(pm_info); if (neg == NULL) return; SSH_DEBUG(SSH_D_LOWOK, ("QM notification call entered, IKE SA %p (neg %p)", pm_info->phase_i->policy_manager_data, neg)); switch (type) { case SSH_IKE_NOTIFY_MESSAGE_RESPONDER_LIFETIME: { int i; SshUInt32 *life; SshUInt32 kb, sec; life = NULL; kb = 0; sec = 0; i = 0; while (i + 4 <= data_size) { SshUInt16 lifetype; SshUInt32 value; if (!ssh_ike_decode_data_attribute_int(data + i, data_size - i, &lifetype, &value, 0L)) { SSH_DEBUG(3, ("ssh_ike_decode_data_attribute_int returned " "error")); return; } switch (lifetype) { case IPSEC_CLASSES_SA_LIFE_TYPE: /* Life type selector */ if (life != NULL) { SSH_DEBUG(3, ("Two life types, without duration")); return; } if (value == IPSEC_VALUES_LIFE_TYPE_SECONDS) { life = &sec; } else if (value == IPSEC_VALUES_LIFE_TYPE_KILOBYTES) { life = &kb; } else { SSH_DEBUG(3, ("Invalid life type")); return; } break; case IPSEC_CLASSES_SA_LIFE_DURATION: /* Life type value */ if (life == NULL) { SSH_DEBUG(3, ("Life duration without type")); return; } if (*life != 0) { SSH_DEBUG(3, ("Same life duration value given twice")); return; } *life = value; life = NULL; } i += ssh_ike_decode_data_attribute_size(data + i, 0L); } if (sec != 0) { if (neg->ed->ipsec_ed->sa_life_seconds == 0 || neg->ed->ipsec_ed->sa_life_seconds > sec) neg->ed->ipsec_ed->sa_life_seconds = sec; } if (kb != 0) { if (neg->ed->ipsec_ed->sa_life_kbytes == 0 || neg->ed->ipsec_ed->sa_life_kbytes > kb) neg->ed->ipsec_ed->sa_life_kbytes = kb; } SSH_DEBUG(SSH_D_NICETOKNOW, ("Received responder lifetime notification: " "life_secs=%lu, life_kbytes=%lu", (unsigned long) sec, (unsigned long) kb)); } default: ssh_log_event(SSH_LOGFACILITY_AUTH, SSH_LOG_INFORMATIONAL, "QM notification `%s' (%d) (size %d bytes) " "from %s%@ for protocol %s spi[0...%d]=%s", ssh_find_keyword_name(ssh_ike_status_keywords, type), type, data_size, pm_info->remote_ip, ikev2_fb_ike_port_render, pm_info->remote_port, ssh_find_keyword_name(ikev2_fb_ike_protocol_identifiers, proto), spi_size - 1, ikev2_fb_util_data_to_hex(buffer, sizeof(buffer), spi, spi_size)); } }
static SshEngineActionRet engine_packet_handle_flow(SshEngine engine, SshEnginePacketContext pc) { SshEngineFlowControl c_flow; SshEngineFlowData d_flow; SshEnginePolicyRule rule; SshEngineFlowStatus undangle_status; SshEngineActionRet ret; Boolean forward; forward = (pc->flags & SSH_ENGINE_PC_FORWARD) != 0; /* We are now in "non-fastpath context" */ ssh_kernel_mutex_assert_is_locked(engine->flow_control_table_lock); c_flow = SSH_ENGINE_GET_FLOW(engine, pc->flow_index); SSH_ASSERT(c_flow->rule_index != SSH_IPSEC_INVALID_INDEX); d_flow = FASTPATH_GET_FLOW(engine->fastpath, pc->flow_index); /* Check the flow is still valid */ if (d_flow->generation != pc->flow_generation || (c_flow->control_flags & SSH_ENGINE_FLOW_C_VALID) == 0) { SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP); SSH_DEBUG(SSH_D_FAIL, ("Flow disappeared.")); FASTPATH_RELEASE_FLOW(engine->fastpath, pc->flow_index); return SSH_ENGINE_RET_FAIL; } /* Check if flow is in drop mode. */ if (d_flow->data_flags & SSH_ENGINE_FLOW_D_DROP_PKTS) { SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_DROP); SSH_DEBUG(SSH_D_NICETOKNOW, ("Flow is in drop mode.")); FASTPATH_RELEASE_FLOW(engine->fastpath, pc->flow_index); return SSH_ENGINE_RET_FAIL; } /* If this is a trigger flow, then it may be that our destination next hop node is still undefined, and it must be defined, before we can undangle this flow. */ if ((c_flow->control_flags & SSH_ENGINE_FLOW_C_TRIGGER) && forward) { SSH_ASSERT((pc->flags & SSH_ENGINE_PC_HIT_TRIGGER) == 0); SSH_DEBUG(SSH_D_NICETOKNOW, ("Packet hit a trigger flow, doing rule execution")); pc->flags |= SSH_ENGINE_PC_HIT_TRIGGER; SSH_ASSERT(pc->rule == NULL); FASTPATH_RELEASE_FLOW(engine->fastpath, pc->flow_index); return SSH_ENGINE_RET_OK; } /* Check if rx_transform_index needs to be updated. */ if (pc->tunnel_id > 1 && (pc->flags & SSH_ENGINE_PC_SKIP_TRD_VERIFY) == 0 && pc->prev_transform_index != SSH_IPSEC_INVALID_INDEX) { int i = 0; Boolean found_match = FALSE; /* Check if packet was decapsulated using transform index in the opposite direction. */ if ((forward && (pc->prev_transform_index == d_flow->reverse_transform_index)) || (!forward && (pc->prev_transform_index == d_flow->forward_transform_index))) found_match = TRUE; /* Check if packet was decapsulated using one of allowed rx transform indexes. */ else { for (i = 0; i < SSH_ENGINE_NUM_RX_TRANSFORMS; i++) { if ((forward && (d_flow->forward_rx_transform_index[i] == SSH_IPSEC_INVALID_INDEX)) || (!forward && (d_flow->reverse_rx_transform_index[i] == SSH_IPSEC_INVALID_INDEX))) break; if ((forward && (pc->prev_transform_index == d_flow->forward_rx_transform_index[i])) || (!forward && (pc->prev_transform_index == d_flow->reverse_rx_transform_index[i]))) { found_match = TRUE; break; } } } /* Packets's prev_transform_index did not match any allowed transform indexes, check packet against rule. */ if (found_match == FALSE) { SSH_DEBUG(SSH_D_LOWOK, ("Packet was decapsulated using a mismatching " "transform index %lx", (unsigned long) pc->prev_transform_index)); ret = engine_packet_handler_verify_sa_selectors(engine, pc); if (ret == SSH_ENGINE_RET_OK) { /* Use an unused slot or move all trd indexes one slot earlier and reuse last slot. */ if (i == SSH_ENGINE_NUM_RX_TRANSFORMS) { for (i = 0; (i + 1) < SSH_ENGINE_NUM_RX_TRANSFORMS; i++) { if (forward) d_flow->forward_rx_transform_index[i] = d_flow->forward_rx_transform_index[i+1]; else d_flow->reverse_rx_transform_index[i] = d_flow->reverse_rx_transform_index[i+1]; } } SSH_ASSERT(i < SSH_ENGINE_NUM_RX_TRANSFORMS); if (forward) d_flow->forward_rx_transform_index[i] = pc->prev_transform_index; else d_flow->reverse_rx_transform_index[i] = pc->prev_transform_index; SSH_DEBUG(SSH_D_LOWOK, ("Inbound %s transform index for flow %d " "updated to %lx", (forward ? "forward" : "reverse"), (int) pc->flow_index, (unsigned long) pc->prev_transform_index)); pc->flags |= SSH_ENGINE_PC_SKIP_TRD_VERIFY; FASTPATH_COMMIT_FLOW(engine->fastpath, pc->flow_index, d_flow); return SSH_ENGINE_RET_RESTART_FLOW_LOOKUP; } FASTPATH_RELEASE_FLOW(engine->fastpath, pc->flow_index); return ret; } } FASTPATH_RELEASE_FLOW(engine->fastpath, pc->flow_index); rule = SSH_ENGINE_GET_RULE(engine, c_flow->rule_index); SSH_DEBUG(SSH_D_NICETOKNOW, ("Packet hit a non-trigger dangling flow!")); /* We should try to undangle the flow and restart the packet */ undangle_status = ssh_engine_flow_undangle(engine, pc->flow_index); switch (undangle_status) { case SSH_ENGINE_FLOW_STATUS_ERROR: SSH_DEBUG(SSH_D_NICETOKNOW, ("Error in undangling flow!")); ssh_engine_free_flow(engine, pc->flow_index); pc->flow_index = SSH_IPSEC_INVALID_INDEX; SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP); return SSH_ENGINE_RET_FAIL; break; case SSH_ENGINE_FLOW_STATUS_REVERSE_TRIGGER: if (!forward) { SSH_DEBUG(SSH_D_FAIL, ("required reverse trigger for tunnel_id=%d", (int) rule->tunnel_id)); /* Fall-through to dangle! */ } case SSH_ENGINE_FLOW_STATUS_DANGLING: SSH_DEBUG(SSH_D_NICETOKNOW, ("Flow still dangling!")); /* Do nothing. Fall-through to trigger generation and THEN drop! */ break; /* The found_flow label requires that flow_table_lock be held. */ case SSH_ENGINE_FLOW_STATUS_WELL_DEFINED: SSH_DEBUG(SSH_D_NICETOKNOW, ("Flow became well-defined. Handling packet!")); /* Pass packet back to fastpath */ engine_packet_continue(pc, SSH_ENGINE_RET_RESTART_FLOW_LOOKUP); return SSH_ENGINE_RET_ASYNC; break; default: SSH_NOTREACHED; } if (rule->type == SSH_ENGINE_RULE_TRIGGER && forward && pc->flow_index != SSH_IPSEC_INVALID_INDEX) { /* This guarantees that we hit a trigger in engine_rule_execute.c */ pc->flags |= SSH_ENGINE_PC_HIT_TRIGGER; /* Ensure that refcounts do not leak. */ SSH_ASSERT(pc->rule == NULL); pc->rule = SSH_ENGINE_GET_RULE(engine, c_flow->rule_index); pc->rule->refcnt++; return SSH_ENGINE_RET_OK; } SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP); return SSH_ENGINE_RET_FAIL; }
static SshRadiusUrlStatus ssh_radius_url_add_avp(SshRadiusUrlAvpSet avp_set, const SshRadiusAvpInfoStruct *avp_info, unsigned char *value, size_t value_len) { unsigned long val; SshRadiusUrlStatus url_status; SSH_PRECOND(avp_set != NULL); SSH_PRECOND(avp_info != NULL); /* Try to allow for "magic keyword" substituion for selected parameter values. */ if (avp_info->value_type == SSH_RADIUS_AVP_VALUE_INTEGER) { url_status = ssh_radius_url_add_avp_by_type(avp_set, avp_info, value, value_len); if (url_status != SSH_RADIUS_URL_STATUS_NONE) return url_status; } /* Perform setting based on type */ switch (avp_info->value_type) { case SSH_RADIUS_AVP_VALUE_TEXT: if (ssh_radius_url_set_avpset_avp(avp_set, avp_info->type, (SshUInt8 *) value, (SshUInt8)value_len) == FALSE) return SSH_RADIUS_URL_OUT_OF_MEMORY; break; case SSH_RADIUS_AVP_VALUE_TAG_INTEGER: case SSH_RADIUS_AVP_VALUE_TAG_STRING: case SSH_RADIUS_AVP_VALUE_IPV6_ADDRESS: SSH_DEBUG(SSH_D_FAIL,("TAG and IPV6 attributes not yet supported")); return SSH_RADIUS_URL_UNKNOWN_AVP_TYPE; break; case SSH_RADIUS_AVP_VALUE_TIME: case SSH_RADIUS_AVP_VALUE_INTEGER: { SshUInt8 number_buf[4]; val = (value != NULL ? ssh_ustrtol(value, NULL, 0) : 0); SSH_PUT_32BIT(number_buf, val); if (ssh_radius_url_set_avpset_avp(avp_set, avp_info->type, number_buf, 4) == FALSE) return SSH_RADIUS_URL_OUT_OF_MEMORY; } break; /* Convert IPv4 address to 32-bit integer */ case SSH_RADIUS_AVP_VALUE_ADDRESS: { SshIpAddrStruct ip_addr; SshUInt8 number_buf[4]; if (value == NULL) return SSH_RADIUS_URL_INVALID_AVP_VALUE; if (ssh_ipaddr_parse(&ip_addr, value) == FALSE) return SSH_RADIUS_URL_INVALID_AVP_VALUE; if (SSH_IP_IS4(&ip_addr) == FALSE) return SSH_RADIUS_URL_INVALID_AVP_VALUE; SSH_PUT_32BIT(number_buf, SSH_IP4_TO_INT(&ip_addr)); if (ssh_radius_url_set_avpset_avp(avp_set, avp_info->type, number_buf, 4) == FALSE) return SSH_RADIUS_URL_OUT_OF_MEMORY; } break; default: SSH_DEBUG(SSH_D_FAIL, ("Unknown RADIUS attribute value type %d!", avp_info->value_type)); return SSH_RADIUS_URL_UNKNOWN_AVP_TYPE; } return SSH_RADIUS_URL_STATUS_SUCCESS; }
Boolean ssh_engine_copy_transform_data(SshEngine engine, SshEnginePacketContext pc) { SshEngineTransformData d_trd; SshEngineFlowData d_flow = NULL; SshEngineFlowControl c_flow; SshEngineTransformControl c_trd; Boolean rv = FALSE; ssh_kernel_mutex_assert_is_locked(engine->flow_control_table_lock); /* Perform some checks to verify that the flow and transform objects belonging to the packet context are still valid. */ if (pc->transform_index != SSH_IPSEC_INVALID_INDEX) { c_trd = SSH_ENGINE_GET_TRD(engine, pc->transform_index); if (c_trd == NULL) { SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP); SSH_DEBUG(SSH_D_FAIL, ("Transform index is not valid anymore")); return FALSE; } } if (pc->flow_index != SSH_IPSEC_INVALID_INDEX) { c_flow = SSH_ENGINE_GET_FLOW(engine, pc->flow_index); if ((c_flow->control_flags & SSH_ENGINE_FLOW_C_VALID) == 0) { SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP); SSH_DEBUG(SSH_D_FAIL, ("Flow disappeared.")); return FALSE; } } if (pc->flow_index != SSH_IPSEC_INVALID_INDEX) { d_flow = FASTPATH_GET_READ_ONLY_FLOW(engine->fastpath, pc->flow_index); /* Check the flow is still valid */ if (d_flow->generation != pc->flow_generation) { SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP); SSH_DEBUG(SSH_D_FAIL, ("Flow disappeared.")); FASTPATH_RELEASE_FLOW(engine->fastpath, pc->flow_index); return FALSE; } } fastpath_copy_flow_data(engine->fastpath, d_flow, pc); if (pc->flow_index != SSH_IPSEC_INVALID_INDEX) FASTPATH_RELEASE_FLOW(engine->fastpath, pc->flow_index); if (pc->transform_index != SSH_IPSEC_INVALID_INDEX) { d_trd = FASTPATH_GET_READ_ONLY_TRD(engine->fastpath, pc->transform_index); if (d_trd == NULL || d_trd->transform == 0) { SSH_ENGINE_MARK_STAT(pc, SSH_ENGINE_STAT_ERRORDROP); SSH_DEBUG(SSH_D_FAIL, ("Transform disappeared.")); FASTPATH_RELEASE_TRD(engine->fastpath, pc->transform_index); return FALSE; } FASTPATH_RELEASE_TRD(engine->fastpath, pc->transform_index); } rv = fastpath_copy_transform_data(engine->fastpath, pc); return rv; }
static SshRadiusUrlStatus ssh_radius_url_do_next(SshRadiusUrlRequest req) { SshRadiusUrlStatus url_status; if (req->url_idx >= req->nurls) return FALSE; SSH_DEBUG(SSH_D_MIDSTART, ("Performing request (index %d) %s", req->url_idx, (req->url[req->url_idx] != NULL ? req->url[req->url_idx] : ssh_ustr("<null>")))); /* First zero all state related to previous req's */ if (req->op_handle != NULL) ssh_operation_abort(req->op_handle); if (req->req != NULL) ssh_radius_client_request_destroy(req->req); if (req->rad_client != NULL) ssh_radius_client_destroy(req->rad_client); if (req->s_info != NULL) ssh_radius_client_server_info_destroy(req->s_info); ssh_radius_url_uninit_params(&req->rad_params); req->s_info = NULL; req->req = NULL; req->op_handle = NULL; req->rad_params.nas_identifier = NULL; req->rad_client = NULL; /* Create a new request from scratch */ url_status = ssh_radius_url_init_params(&req->rad_params, req->url[req->url_idx]); if (url_status != SSH_RADIUS_URL_STATUS_SUCCESS) return url_status; req->s_info = ssh_radius_client_server_info_create(); if (req->s_info == NULL) return SSH_RADIUS_URL_OUT_OF_MEMORY; url_status = ssh_radius_url_add_server(req->s_info, req->url[req->url_idx]); if (url_status != SSH_RADIUS_URL_STATUS_SUCCESS) return url_status; req->rad_client = ssh_radius_client_create(&req->rad_params); if (req->rad_client == NULL) return SSH_RADIUS_URL_OUT_OF_MEMORY; req->req = ssh_radius_client_request_create(req->rad_client, SSH_RADIUS_ACCESS_REQUEST); if (req->req == NULL) return SSH_RADIUS_URL_OUT_OF_MEMORY; /* Add AVP's so that the ones specified on the command line have precedence */ { SshRadiusUrlAvpSet avp_url, avp_comb; url_status = ssh_radius_url_create_avpset(&avp_url, req->url[req->url_idx]); if (url_status != SSH_RADIUS_URL_STATUS_SUCCESS) return url_status; avp_comb = ssh_radius_url_add_avpset(&req->avp_set, avp_url); if (avp_comb == NULL) { ssh_radius_url_destroy_avpset(avp_url); return SSH_RADIUS_URL_OUT_OF_MEMORY; } if (ssh_radius_url_add_avps(req->req, avp_comb) == FALSE) { ssh_radius_url_destroy_avpset(avp_comb); ssh_radius_url_destroy_avpset(avp_url); return SSH_RADIUS_URL_OUT_OF_MEMORY; } ssh_radius_url_destroy_avpset(avp_comb); ssh_radius_url_destroy_avpset(avp_url); } /* .. Finally send the request */ req->op_handle = ssh_radius_client_request(req->req, req->s_info, ssh_radius_url_cb, req); if (req->op_handle == NULL) return SSH_RADIUS_URL_OUT_OF_MEMORY; return SSH_RADIUS_URL_STATUS_SUCCESS; }
/* Read binary file from the disk giving a size limit for the file. Return mallocated buffer and the size of the buffer. If the reading of file failes return FALSE. If the file name is NULL or "-" then read from the stdin. The size_limit is in bytes. If zero is used, the read file will try to read the whole file. If the file size exceeds the size_limit (given in bytes), FALSE is returned. */ Boolean ssh_read_file_with_limit(const char *file_name, SshUInt32 size_limit, unsigned char **buf, size_t *buf_len) { FILE *fp = NULL; unsigned char *iobuf = NULL, *tmp; size_t len, plen, growth, t, offset, ret; #ifdef WINDOWS WCHAR *file = NULL; DWORD name_len; #endif /* WINDOWS */ /* Read the file */ if (file_name == NULL || strcmp(file_name, "-") == 0) { fp = stdin; file_name = NULL; } else #ifdef WINDOWS { if ((name_len = MultiByteToWideChar(CP_UTF8, 0, file_name, -1, NULL, 0)) == 0) { SSH_DEBUG(SSH_D_FAIL, ("Multibyte conversion failed")); goto failed; } if (!(file = ssh_malloc((name_len) * sizeof *file))) { SSH_DEBUG(SSH_D_FAIL, ("allocation failed for file name")); goto failed; } if ((MultiByteToWideChar(CP_UTF8, 0, file_name, -1, file, name_len)) == 0) { SSH_DEBUG(SSH_D_FAIL, ("Multibyte conversion failed")); goto failed; } fp = _wfopen(file, L"rb"); } #else /* WINDOWS */ fp = fopen(file_name, "rb"); #endif /* WINDOWS */ if (fp == NULL) { SSH_DEBUG(SSH_D_FAIL, ("Can't open file for reading")); goto failed; } offset = 0; growth = len = plen = FILEBUF_SIZE; if ((iobuf = ssh_malloc(len)) == NULL) goto failed; /* Read the file */ while ((ret = fread(iobuf + offset, 1, growth, fp)) == growth) { offset += growth; SSH_FILEIO_CHECK_MAX_SIZE; /* Fibonacci series on buffer size growth */ t = len; len += plen; growth = plen; plen = t; SSH_DEBUG(SSH_D_HIGHOK, ("Growing input buffer from %zd to %zd bytes", plen, len)); if ((tmp = ssh_realloc(iobuf, plen, len)) == NULL) goto failed; iobuf = tmp; } SSH_DEBUG(SSH_D_HIGHOK, ("Last read from file %zd bytes to offset %zd, total %zd bytes.", ret, offset, ret+offset)); if (ferror(fp)) goto failed; offset += ret; SSH_FILEIO_CHECK_MAX_SIZE; #ifdef WINDOWS if (file) { fclose(fp); ssh_free(file); } #else /* WINDOWS */ if (file_name) fclose(fp); #endif /* WINDOWS */ *buf = iobuf; *buf_len = offset; return TRUE; failed: #ifdef WINDOWS if (file) ssh_free(file); #endif /* WINDOWS */ if (file_name && fp) fclose(fp); if (iobuf) ssh_free(iobuf); return FALSE; }
SshRadiusUrlStatus ssh_radius_url_init_avpset(SshRadiusUrlAvpSet set, unsigned char *url) { unsigned char *path, *type; const unsigned char *key, *value; size_t key_length, value_length; SshUrlQuery query; const SshRadiusAvpInfoStruct *avp_info; SshRadiusUrlStatus url_status; SshRadiusUrlStatus bad_url_status; url_status = SSH_RADIUS_URL_STATUS_NONE; set->avp = NULL; set->navps = 0; if (url == NULL) return SSH_RADIUS_URL_STATUS_SUCCESS; path = ssh_radius_get_url_path(url); type = NULL; query = NULL; if (path != NULL && path[0] != '\0') { if (ssh_url_parse_get(path, NULL, NULL, &type, &query, NULL, FALSE) != SSH_URL_OK) { url_status = SSH_RADIUS_URL_AVPLIST_MALFORMED; goto fail; } } if (query != NULL) { SshUrlEntry entry; bad_url_status = SSH_RADIUS_URL_STATUS_NONE; for (entry = ssh_url_query_enumerate_start(query); entry; entry = ssh_url_query_enumerate_next(query, entry)) { key = ssh_url_entry_key(entry, &key_length); value = ssh_url_entry_value(entry, &value_length); if (key != NULL) { avp_info = ssh_radius_avp_info_name((char *)key); if (avp_info == NULL) { SSH_DEBUG(SSH_D_FAIL, ("unrecognized RADIUS attribute name: %s", key)); bad_url_status = SSH_RADIUS_URL_UNKNOWN_AVP_TYPE; } else { url_status = ssh_radius_url_add_avp(set, avp_info, (unsigned char *) value, value_length); if (url_status != SSH_RADIUS_URL_STATUS_SUCCESS) { SSH_DEBUG(SSH_D_FAIL, ("failed to add attribute %s to " "request",key)); bad_url_status = url_status; } } } } ssh_url_query_free(query); if (bad_url_status != SSH_RADIUS_URL_STATUS_NONE) { url_status = bad_url_status; goto fail; } } if (type != NULL) ssh_free(type); ssh_free(path); return SSH_RADIUS_URL_STATUS_SUCCESS; fail: if (path != NULL) ssh_free(path); if (type != NULL) ssh_free(type); return url_status; }
SocksError ssh_socks5_server_generate_reply(SshBuffer buffer, SocksInfo socksinfo) { unsigned char *data; int port, ip_addr_len; unsigned int atyp; size_t len; SshIpAddrStruct ip_addr; port = ssh_inet_get_port_by_service(socksinfo->port, ssh_custr("tcp")); if (port >= 65536 || port <= 0) return SSH_SOCKS_ERROR_INVALID_ARGUMENT; if (!ssh_ipaddr_parse(&ip_addr, socksinfo->ip)) { atyp = SSH_SOCKS5_ATYP_FQDN; ip_addr_len = ssh_ustrlen(socksinfo->ip); } else if (SSH_IP_IS4(&ip_addr)) { atyp = SSH_SOCKS5_ATYP_IPV4; ip_addr_len = 4; } else if (SSH_IP_IS6(&ip_addr)) { atyp = SSH_SOCKS5_ATYP_IPV6; ip_addr_len = 16; } else { SSH_DEBUG(2, ("IP-address is of unknown type.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } len = 6 + ip_addr_len; if (atyp == SSH_SOCKS5_ATYP_FQDN) /* Length field. */ len += 1; if (ssh_buffer_append_space(buffer, &data, len) != SSH_BUFFER_OK) { SSH_DEBUG(2, ("Failed to allocate reply buffer.")); return SSH_SOCKS_ERROR_INVALID_ARGUMENT; } *data++ = socksinfo->socks_version_number; *data++ = socksinfo->command_code; *data++ = 0; /* RSV. */ *data++ = atyp; if (atyp == SSH_SOCKS5_ATYP_FQDN) { *data++ = ip_addr_len; memmove(data, socksinfo->ip, ip_addr_len); data += ip_addr_len; } else { int len; SSH_IP_ENCODE(&ip_addr, data, len); SSH_ASSERT(ip_addr_len == len); data += len; } SSH_PUT_16BIT(data, port); return SSH_SOCKS_SUCCESS; }
static Boolean ssh_dns_resolver_get_xp(SshDNSResolver resolver) { HMODULE module; p_get_adapters_addresses get_adapters_addresses; IP_ADAPTER_ADDRESSES *adapter_addresses, *adapter; IP_ADAPTER_DNS_SERVER_ADDRESS *dns_address; SshUInt32 size; SshUInt32 result; SshIpAddrStruct address[1]; Boolean added = FALSE; module = LoadLibrary(TEXT("iphlpapi")); if (module == NULL) { SSH_DEBUG(SSH_D_FAIL, ("Unable to load iphelper library")); return FALSE; } get_adapters_addresses = (p_get_adapters_addresses) GetProcAddress(module, TEXT("GetAdaptersAddresses")); if (get_adapters_addresses == NULL) { SSH_DEBUG(SSH_D_FAIL, ("Could not find GetAdaptersAddresses" " function in the library")); goto exit_function; } result = get_adapters_addresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST, NULL, NULL, &size); if (result != ERROR_BUFFER_OVERFLOW) { SSH_DEBUG(SSH_D_FAIL, ("Unable to get the size of Interface info. Error is %d", result)); goto exit_function; } adapter_addresses = ssh_calloc(1, size); if (adapter_addresses == NULL) { SSH_DEBUG(SSH_D_FAIL, ("Unable to allocate memory")); goto exit_function; } result = get_adapters_addresses(AF_UNSPEC, GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_FRIENDLY_NAME | GAA_FLAG_SKIP_MULTICAST, NULL, adapter_addresses, &size); if (result != NO_ERROR) { SSH_DEBUG(SSH_D_FAIL, ("Call to GetAdaptersAddresses failed." " Error 0x%x", result)); goto exit_function; } adapter = adapter_addresses; while (adapter) { if ((adapter->OperStatus != IfOperStatusUp) || (adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK) || (adapter->IfType == IF_TYPE_TUNNEL)) goto loop; dns_address = (PIP_ADAPTER_DNS_SERVER_ADDRESS) adapter->FirstDnsServerAddress; while (dns_address) { if (((SOCKADDR *)dns_address->Address.lpSockaddr)->sa_family == AF_INET) SSH_IP4_DECODE(address, &((PSOCKADDR_IN)dns_address->Address.lpSockaddr) ->sin_addr.s_addr); else if (((SOCKADDR *)dns_address->Address.lpSockaddr)->sa_family == AF_INET6) SSH_IP6_DECODE(address, &((PSOCKADDR_IN6)dns_address->Address.lpSockaddr) ->sin6_addr.s6_addr); else goto next; ssh_dns_resolver_safety_belt_add(resolver, 1, address); added = TRUE; SSH_DEBUG(SSH_D_NICETOKNOW, ("Added DNS server %@", ssh_ipaddr_render, address)); next: dns_address = dns_address->Next; } loop: adapter = adapter->Next; } ssh_free(adapter_addresses); exit_function: FreeLibrary(module); return added; }