int hip_daemon_bind_socket(int socket, struct sockaddr *sa) { int err = 0, port = 0, on = 1; struct sockaddr_in6 *addr = (struct sockaddr_in6 *) sa; HIP_ASSERT(addr->sin6_family == AF_INET6); errno = 0; if (setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) == -1) { HIP_DEBUG ("Failed to set socket option SO_REUSEADDR %s \n", strerror(errno)); } if (addr->sin6_port) { HIP_DEBUG("Bind to fixed port %d\n", addr->sin6_port); err = bind(socket,(struct sockaddr *)addr, sizeof(struct sockaddr_in6)); err = -errno; goto out_err; } /* try to bind first to a priviledged port and then to ephemeral */ port = 1000; while (port++ < 61000) { _HIP_DEBUG("trying bind() to port %d\n", port); addr->sin6_port = htons(port); err = bind(socket,(struct sockaddr *)addr, hip_sockaddr_len(addr)); if (err == -1) { if (errno == EACCES) { /* Ephemeral ports: /proc/sys/net/ipv4/ip_local_port_range */ _HIP_DEBUG("Skipping to ephemeral range\n"); port = 32768; errno = 0; err = 0; } else if (errno == EADDRINUSE) { _HIP_DEBUG("Port %d in use, skip\n", port); errno = 0; err = 0; } else { HIP_ERROR("Error %d bind() wasn't succesful\n", errno); err = -1; goto out_err; } } else { _HIP_DEBUG("Bind() to port %d successful\n", port); goto out_err; } } if (port == 61000) { HIP_ERROR("All privileged ports were occupied\n"); err = -1; } out_err: return err; }
/** * hip_calculate_shared_secret - Creates a shared secret based on the * public key of the peer (passed as an argument) and own DH private key * (created beforehand). * @param public_value Peer's Diffie-Hellman public key * @param group_id the Diffie-Hellman group ID * @param len the length of the public value * @param buffer Buffer that holds enough space for the shared secret. * @param bufsize size of the buffer * * @return the length of the shared secret in octets if successful, * or -1 if an error occured. */ int hip_calculate_shared_secret(uint8_t *public_value, uint8_t group_id, signed int len, u8* buffer, int bufsize) { int err; DH *tmp; /* * First check that we have the key available. * Then encode it into the buffer */ if (dh_table[group_id] == NULL) { tmp = hip_generate_dh_key(group_id); _HIP_DEBUG("Generating key\n"); dh_table[group_id] = tmp; if (dh_table[group_id] == NULL) { HIP_ERROR("Unsupported DH group: %d\n", group_id); return -1; } } err = hip_gen_dh_shared_key(dh_table[group_id], public_value, len, buffer, bufsize); if (err < 0) { HIP_ERROR("Could not create shared secret\n"); return -1; } _HIP_HEXDUMP("Peer DH pubkey", public_value, len); _HIP_HEXDUMP("Shared key", buffer, bufsize); return err; }
/** * Build and append a HIP CHALLENGE_RESPONSE to the message. * * @param msg the message where the CHALLENGE_RESPONSE is appended * @param request the received CHALLENGE_REQUEST parameter for this response * @param solution the solution for the puzzle in the CHALLENGE_REQUEST * * @return zero for success, or negative value on error */ int hip_build_param_challenge_response(struct hip_common *const msg, const struct hip_challenge_request *const request, const uint8_t solution[PUZZLE_LENGTH]) { struct hip_challenge_response response; static const size_t min_length = sizeof(response) - sizeof(response.tlv) - sizeof(response.opaque); if (!request || !solution) { HIP_ERROR("Unexpected input parameter values (NULL).\n"); return -1; } const int opaque_len = hip_challenge_request_opaque_len(request); /* note: the length cannot be calculated with calc_param_len() */ hip_set_param_contents_len(&response.tlv, min_length + opaque_len); hip_set_param_type(&response.tlv, HIP_PARAM_CHALLENGE_RESPONSE); memcpy(response.J, solution, PUZZLE_LENGTH); response.K = request->K; response.lifetime = request->lifetime; memcpy(response.opaque, request->opaque, opaque_len); if (hip_build_param(msg, &response)) { HIP_ERROR("failed to build parameter\n"); return -1; } return 0; }
/** * Handle LOCATOR parameter in first update packet. * * @param packet_type The packet type of the control message (RFC 5201, 5.3.) * @param ha_state The host association state (RFC 5201, 4.4.1.) * @param ctx Pointer to the packet context, containing all information for * the packet handling (received message, source and destination * address, the ports and the corresponding entry from the host * association database). * * @return zero on success, or negative error value on error. */ int hip_handle_locator_parameter(UNUSED const uint8_t packet_type, UNUSED const uint32_t ha_state, struct hip_packet_context *ctx) { int locator_addr_count = 0; union hip_locator_info_addr *locator_info_addr = NULL; struct hip_locator_info_addr_item *locator_address_item = NULL; struct update_state *localstate = NULL; struct hip_locator *locator = NULL; if (hip_classify_update_type(ctx->input_msg) == FIRST_UPDATE_PACKET) { if (!(locator = hip_get_param_readwrite(ctx->input_msg, HIP_PARAM_LOCATOR))) { HIP_ERROR("no LOCATOR parameter found\n"); return -1; } locator_addr_count = hip_get_locator_addr_item_count(locator); HIP_DEBUG("LOCATOR has %d address(es), loc param len=%d\n", locator_addr_count, hip_get_param_total_len(locator)); // Empty the addresses_to_send_echo_request list before adding the // new addresses localstate = lmod_get_state_item(ctx->hadb_entry->hip_modular_state, "update"); HIP_DEBUG("hip_get_state_item returned localstate: %p\n", localstate); hip_remove_addresses_to_send_echo_request(localstate); locator_address_item = (struct hip_locator_info_addr_item *) (locator + 1); HIP_DEBUG_IN6ADDR("Adding IP source address to locator set", &ctx->src_addr); if (!hip_add_address_to_send_echo_request(localstate, ctx->src_addr)) { HIP_ERROR("Adding source address to the container for update locators failed!\n"); return -1; } for (int i = 0; i < locator_addr_count; i++) { locator_info_addr = hip_get_locator_item(locator_address_item, i); const struct in6_addr *const peer_addr = hip_get_locator_item_address(locator_info_addr); if (ipv6_addr_cmp(&ctx->src_addr, peer_addr) != 0) { HIP_DEBUG_IN6ADDR("adding locator", peer_addr); if (!hip_add_address_to_send_echo_request(localstate, *peer_addr)) { HIP_ERROR("Adding an address to the container for update locators failed!\n"); return -1; } } } hip_print_addresses_to_send_update_request(ctx->hadb_entry); } return 0; }
/* * execute the given the test cases in the given test suite in the given * testspace * * argc: the number of arguments to the unit test command line tool * argv: the command line arguments in an array of pointers; the name or the * program, testspace id, testsuite id and testcase id * * All "id" arguments are given as numbers. The numbers can be mapped to * symbolic actions from the source file only. Id "0" or the string "all" * means that all entries from id should be selected. * * A shorthand for running all of the test cases is "unittest all". It is * equivalent to "unittest all all all". * * Returns 0 if no errors were found during the executions of test cases. * Otherwise returns the number of errors found. * */ int main(int argc, char *argv[]) { int i; uint16_t err = 0; uint16_t test_type[TEST_TYPE_MAX]; char *testsuite_name, *testcase_name; char err_log[ERR_MSG_MAX_LEN] = ""; /* Default value is zero (= execute "all"). This is useful in the case the arguments contain just "all" or "all all". */ test_type[TEST_SPACE] = 0; test_type[TEST_SUITE] = 0; test_type[TEST_CASE] = 0; if (argc < 2 || argc > ARG_NUMBER) { err = -EINVAL; HIP_ERROR("Expected %d args, got %d\n", ARG_NUMBER - 1, argc); HIP_ERROR("usage: %s\n", unittest_usage); goto out; } /* Map symbolic arguments to numbers. */ for (i = 0; i < argc - 1; i++) { test_type[i] = (!strcmp(argv[i + 1], "all")) ? 0 : (uint16_t) atoi(argv[i + 1]); } HIP_DEBUG("Executing testspace=%d testsuite=%d testcase=%d\n", test_type[TEST_SPACE], test_type[TEST_SUITE], test_type[TEST_CASE]); /* Kernel test are executed using a unit test case which needs the test suite id and case id so that the kernel module can execute correct test suites and cases. This is problem because test cases do accept any parameters. but it can be bypassed by using global variables. Note that the userspace test cases do not need these variables. */ suiteid = test_type[TEST_SUITE]; caseid = test_type[TEST_CASE]; err = hip_run_unit_test_space(&unit_test_space, test_type[TEST_SPACE], test_type[TEST_SUITE], test_type[TEST_CASE], err_log, ERR_MSG_MAX_LEN); if (err) HIP_ERROR("\n===Unit Test Summary===\nTotal %d errors:\n%s\n", err, err_log); else HIP_INFO("\n===Unit Test Summary===\nAll tests passed, no errors!\n"); out: return err; }
void hip_delete_sa(u32 spi, struct in6_addr *peer_addr, struct in6_addr *dst_addr, int direction, hip_ha_t *entry) { int so, len, err = 0; struct sockaddr_storage ss_addr, dd_addr; struct sockaddr *saddr; struct sockaddr *daddr; in_port_t sport, dport; /* @todo: sport and dport should be used! */ if (direction == HIP_SPI_DIRECTION_OUT) { sport = entry->local_udp_port; dport = entry->peer_udp_port; entry->outbound_sa_count--; if (entry->outbound_sa_count < 0) { HIP_ERROR("Warning: out sa count negative\n"); entry->outbound_sa_count = 0; } } else { sport = entry->peer_udp_port; dport = entry->local_udp_port; entry->inbound_sa_count--; if (entry->inbound_sa_count < 0) { HIP_ERROR("Warning: in sa count negative\n"); entry->inbound_sa_count = 0; } } saddr = (struct sockaddr*) &ss_addr; daddr = (struct sockaddr*) &dd_addr; HIP_DEBUG("\n"); HIP_DEBUG("spi=0x%x\n", spi); HIP_DEBUG_IN6ADDR("peer_addr", peer_addr); HIP_DEBUG_IN6ADDR("dst_addr", dst_addr); // Sanity check HIP_IFEL((!peer_addr || !dst_addr), -1, "Addresses not valid when deleting SA's\n"); HIP_IFEL(((so = pfkey_open()) < 0), -1, "ERROR in opening pfkey socket: %s\n", ipsec_strerror()); get_sock_addr_from_in6(saddr, peer_addr); get_sock_addr_from_in6(daddr, dst_addr); HIP_IFEBL(((len = pfkey_send_delete(so, SADB_SATYPE_ESP, HIP_IPSEC_DEFAULT_MODE, saddr, daddr, spi))<0), -1, pfkey_close(so), "ERROR in deleting sa %s", ipsec_strerror()); out_err: return; }
/* getter function for a specific element of the given hash chain * * @param hash_chain hash chain from which the element should be returned * @param idx index to the hash chain element * @return element of the given hash chain */ static unsigned char *hchain_element_by_index(const struct hash_chain *hash_chain, const int idx) { unsigned char *element = NULL; int err = 0; HIP_ASSERT(hash_chain); if (idx >= 0 && idx < hash_chain->hchain_length) { element = &hash_chain->elements[idx * hash_chain->hash_length]; } else { HIP_ERROR("Element from uninited hash chain or out-of-bound element requested!"); err = -1; goto out_err; } HIP_HEXDUMP("Hash chain element: ", element, hash_chain->hash_length); out_err: if (err) { element = NULL; } return element; }
/** * Add ECHO_REQUEST parameter to second update packet. * * @param packet_type The packet type of the control message (RFC 5201, 5.3.) * @param ha_state The host association state (RFC 5201, 4.4.1.) * @param ctx Pointer to the packet context, containing all information for * the packet handling (received message, source and destination * address, the ports and the corresponding entry from the host * association database). * * @return zero on success, or negative error value on error. */ int hip_add_echo_request_param(UNUSED const uint8_t packet_type, UNUSED const uint32_t ha_state, struct hip_packet_context *ctx) { int err = 0; if (hip_classify_update_type(ctx->input_msg) == FIRST_UPDATE_PACKET) { // Randomize the echo response opaque data before sending ECHO_REQUESTS. // Notice that we're using the same opaque value for the identical // UPDATE packets sent between different address combinations. RAND_bytes(ctx->hadb_entry->echo_data, sizeof(ctx->hadb_entry->echo_data)); HIP_HEXDUMP("ECHO_REQUEST in the host association", ctx->hadb_entry->echo_data, sizeof(ctx->hadb_entry->echo_data)); if (hip_build_param_echo(ctx->output_msg, ctx->hadb_entry->echo_data, sizeof(ctx->hadb_entry->echo_data), 1, 1)) { HIP_ERROR("Building of ECHO_REQUEST failed\n"); return -1; } } return err; }
/** * Build and append a HIP CHALLENGE_REQUEST to the message. * * @param msg the message where the CHALLENGE_REQUEST is appended * @param difficulty the puzzle difficulty for the CHALLENGE_REQUEST * @param lifetime lifetime the puzzle nonce * @param opaque the nonce (challenge) of the CHALLENGE_REQUEST * @param opaque_len the length of the nonce * * @return zero for success, or negative value on error */ int hip_build_param_challenge_request(struct hip_common *const msg, const uint8_t difficulty, const uint8_t lifetime, const uint8_t *opaque, const uint8_t opaque_len) { struct hip_challenge_request request; static const size_t min_length = sizeof(request) - sizeof(request.tlv) - sizeof(request.opaque); HIP_ASSERT(opaque); /* note: the length cannot be calculated with calc_param_len() */ hip_set_param_contents_len(&request.tlv, min_length + opaque_len); hip_set_param_type(&request.tlv, HIP_PARAM_CHALLENGE_REQUEST); /* only the random_j_k is in host byte order */ request.K = difficulty; request.lifetime = lifetime; memcpy(&request.opaque, opaque, opaque_len); if (hip_build_param(msg, &request) != 0) { HIP_ERROR("failed to build parameter\n"); return -1; } return 0; }
/** * Handle ECHO_REQUEST_SIGNED parameter. * * @param packet_type The packet type of the control message (RFC 5201, 5.3.) * @param ha_state The host association state (RFC 5201, 4.4.1.) * @param ctx Pointer to the packet context, containing all information for * the packet handling (received message, source and destination * address, the ports and the corresponding entry from the host * association database). * * @return zero on success, or negative error value on error. */ int hip_handle_echo_request_sign_param(UNUSED const uint8_t packet_type, UNUSED const uint32_t ha_state, struct hip_packet_context *ctx) { const struct hip_echo_request *echo_request = NULL; if (!(echo_request = hip_get_param(ctx->input_msg, HIP_PARAM_ECHO_REQUEST_SIGN))) { HIP_DEBUG("no ECHO_REQUEST_SIGN parameter in UPDATE packet, skipping\n"); /* This condition is no error! There simply was no request by the peer * to add a ECHO_RESPONSE_SIGN parameter to the outbound message. */ return 0; } HIP_DEBUG("echo opaque data len=%d\n", hip_get_param_contents_len(echo_request)); HIP_HEXDUMP("ECHO_REQUEST_SIGN ", (const uint8_t *) echo_request + sizeof(struct hip_tlv_common), hip_get_param_contents_len(echo_request)); if (hip_build_param_echo(ctx->output_msg, (const uint8_t *) echo_request + sizeof(struct hip_tlv_common), hip_get_param_contents_len(echo_request), 1, 0)) { HIP_ERROR("Building of ECHO_RESPONSE_SIGN failed\n"); return -1; } return 0; }
/** * No description. */ int hip_set_opportunistic_mode(const struct hip_common *msg){ int err = 0; unsigned int *mode = NULL; mode = hip_get_param_contents(msg, HIP_PARAM_UINT); if (!mode) { err = -EINVAL; goto out_err; } HIP_DEBUG("mode=%d\n", *mode); if(*mode == 0 || *mode == 1 || *mode == 2){ opportunistic_mode = *mode; } else { HIP_ERROR("Invalid value for opportunistic mode\n"); err = -EINVAL; goto out_err; } memset(msg, 0, HIP_MAX_PACKET); HIP_IFE(hip_build_user_hdr(msg, (opportunistic_mode == 2 ? SO_HIP_SET_OPPTCP_ON : SO_HIP_SET_OPPTCP_OFF), 0), -1); hip_set_opportunistic_tcp_status(msg); out_err: return err; }
/** * hip_insert_dh - Insert the current DH-key into the buffer * * If a DH-key does not exist, we will create one. * @return >0 if ok, -1 if errors */ int hip_insert_dh(u8 *buffer, int bufsize, int group_id) { size_t res; DH *tmp; /* * First check that we have the key available. * Then encode it into the buffer */ if (dh_table[group_id] == NULL) { tmp = hip_generate_dh_key(group_id); dh_table[group_id] = tmp; if (dh_table[group_id] == NULL) { HIP_ERROR("DH key %d not found and could not create it\n", group_id); return -1; } } tmp = dh_table[group_id]; res = hip_encode_dh_publickey(tmp, buffer, bufsize); if (res < 0) { HIP_ERROR("Encoding error\n"); res = -3; goto err_free; } _HIP_HEXDUMP("DH public key: ", buffer, res); err_free: return res; }
int hip_flush_all_policy() { int so, len, err = 0; HIP_DEBUG("\n"); HIP_IFEL(((so = pfkey_open()) < 0), -1, "ERROR in opening pfkey socket: %s\n", ipsec_strerror()); HIP_DEBUG("FLushing all SP's\n"); HIP_IFEBL(((len = pfkey_send_spdflush(so))<0), -1, pfkey_close(so), "ERROR in flushing policies %s\n", ipsec_strerror()); HIP_DEBUG("FLushing all SP's was successful\n"); return len; out_err: HIP_ERROR("FLushing all SP's\n"); return err; }
/** * Initialize ESPv6-based raw socket * * @param sock the created raw socket will be written here * * @return zero on success, non-zero on error */ static int hip_firewall_init_raw_sock_esp_v6(int *sock) { int on = 1, off = 0, err = 0; *sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ESP); HIP_IFE(setsockopt(*sock, IPPROTO_IPV6, IPV6_RECVERR, &off, sizeof(off)), -1); HIP_IFE(setsockopt(*sock, IPPROTO_IPV6, IPV6_2292PKTINFO, &on, sizeof(on)), -1); HIP_IFE(setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)), -1); out_err: if (err) { HIP_ERROR("init sock esp v4\n"); } return err; }
/** * Add ESP_INFO parameter to second update packet. * * @param packet_type The packet type of the control message (RFC 5201, 5.3.) * @param ha_state The host association state (RFC 5201, 4.4.1.) * @param ctx Pointer to the packet context, containing all information for * the packet handling (received message, source and destination * address, the ports and the corresponding entry from the host * association database). * * @return zero on success, or negative error value on error. */ int hip_add_esp_info_param(UNUSED const uint8_t packet_type, UNUSED const uint32_t ha_state, struct hip_packet_context *ctx) { if (hip_classify_update_type(ctx->input_msg) == FIRST_UPDATE_PACKET) { if (hip_build_param_esp_info(ctx->output_msg, ctx->hadb_entry->current_keymat_index, ctx->hadb_entry->spi_inbound_current, ctx->hadb_entry->spi_inbound_current)) { HIP_ERROR("Building of ESP_INFO param failed\n"); return -1; } } return 0; }
/** * hip_run_unit_test_space - select and run tests in the unit test space * @param unit_space pointer to an unit space structure * @param spaceid test space id (zero = all spaces) * @param suiteid test suite number (zero = all suites) * @param caseid test case nuber (zero = all cases) * @param err_log a string where the error log is stored * @param err_max the capacity of the string * * This is only needed in the userspace for selecting and launching the * test cases in the correct testspace (kernelspace or userspace). * * @return the number of errors occurred when the test cases were run. */ uint16_t hip_run_unit_test_space(struct hip_unit_test_space *unit_space, uint16_t spaceid, uint16_t suiteid, uint16_t caseid, void *err_log, size_t err_max) { /* Spaceid is indexed in the range [1..n] because zero is reserved for executing in all spaces. However, xx_space variables below are indexed in the range [0..n-1] for direct access into the corresponding array. */ uint16_t first_space, current_space, last_space; size_t err_len = 0, space_left = 0; void *err_index = err_log; uint16_t err = 0; first_space = (spaceid == 0) ? 0 : spaceid - 1; last_space = (spaceid == 0) ? unit_space->nbr - 1 : spaceid - 1; if (last_space > unit_space->nbr - 1) { HIP_ERROR("Trying to access illegal unit test spaceid (%d/%d).", last_space, unit_space->nbr - 1); err = 1; goto out; } /* make sure that the string will null padded even if nothing will actually be written to err_log in the call to test suite */ if (err_max > 0) ((char *)err_log)[0] = '\0'; _HIP_DEBUG("for index: %d-%d\n", first_space, last_space); for (current_space = first_space; current_space <= last_space; current_space++) { space_left = ((void *)err_log) - err_index + err_max; /* if no space - ignore error messages, just count errors */ if (space_left <= 0) err_len = 0; err += hip_run_unit_test_case(unit_space->test_suite_list[current_space], suiteid, caseid, err_index, space_left); err_len = strlen(err_index); err_index += err_len; } out: return err; }
/** * Initialize the middlebox firewall application. * This sets up the firewall's policies. * * @param policy_file the configuration file (in libconfig format) that specifies * the firewall's policy. If NULL, a default policy is used. * * @return 0 on success, negative on error */ int signaling_hipfw_feedback_init(const char *key_file, const char *cert_file) { int err = 0; /* Load the host identity */ if (HIP_DEFAULT_HIPFW_ALGO == HIP_HI_ECDSA) { load_ecdsa_private_key(key_file, &ecdsa_key); hip_any_key_to_hit(ecdsa_key, &our_hit, 0, HIP_HI_ECDSA); } else if (HIP_DEFAULT_HIPFW_ALGO == HIP_HI_RSA) { load_rsa_private_key(key_file, &rsa_key); hip_any_key_to_hit(rsa_key, &our_hit, 0, HIP_HI_RSA); } HIP_DEBUG("Successfully Loaded the MiddleBox key.\n"); HIP_INFO_HIT("Our hit: ", &our_hit); mb_cert = load_x509_certificate(cert_file); /* Sockets */ hipfw_nat_sock_output_udp = init_raw_sock_v4(IPPROTO_UDP); if (hipfw_nat_sock_output_udp > 0) { HIP_DEBUG("Successfully initialized nat output socket. \n"); } else { HIP_DEBUG("Failed to bind output socket. \n"); } if (rtnl_open_byproto(&hipfw_nl_route, RTMGRP_LINK | RTMGRP_IPV6_IFADDR | IPPROTO_IPV6 | RTMGRP_IPV4_IFADDR | IPPROTO_IP, NETLINK_ROUTE) < 0) { err = 1; HIP_ERROR("Routing socket error: %s\n", strerror(errno)); goto out_err; } else { HIP_DEBUG("Successfully opened netlink socket \n"); } /* flush ip table rules to not catch our own notify... */ system_print("iptables -D HIPFW-OUTPUT 1"); system_print("iptables -D HIPFW-OUTPUT 1"); out_err: return err; }
/** * Handle ESP_INFO parameter in first and second update packet. * * @param packet_type The packet type of the control message (RFC 5201, 5.3.) * @param ha_state The host association state (RFC 5201, 4.4.1.) * @param ctx Pointer to the packet context, containing all information for * the packet handling (received message, source and destination * address, the ports and the corresponding entry from the host * association database). * * @return zero on success, or negative error value on error. */ int hip_handle_esp_info_param(UNUSED const uint8_t packet_type, UNUSED const uint32_t ha_state, struct hip_packet_context *ctx) { const struct hip_esp_info *esp_info = NULL; const enum update_types update_type = hip_classify_update_type(ctx->input_msg); if (update_type == FIRST_UPDATE_PACKET || update_type == SECOND_UPDATE_PACKET) { if (!(esp_info = hip_get_param(ctx->input_msg, HIP_PARAM_ESP_INFO))) { HIP_ERROR("No ESP_INFO parameter found\n"); return -1; } // set the new spi value for the association // TODO add rekeying functionality here ctx->hadb_entry->spi_outbound_new = ntohl(esp_info->new_spi); } return 0; }
/** * opendht_read_response - Reads from the given socket and parses the XML RPC response * @param sockfd Socket to be used with the send * @param answer Buffer where the response value will be saved * * @return Returns integer, same as in read_packet_content * TODO: see read_packet_content */ int opendht_read_response(int sockfd, char * answer) { int ret = 0, pton_ret = 0; int bytes_read = 0, total = 0; char read_buffer[HIP_MAX_PACKET]; //char tmp_buffer[HIP_MAX_PACKET]; struct in_addr ipv4; struct in6_addr ipv6 = {0}; if (sockfd <= 0 || answer == NULL) { HIP_ERROR("sockfd=%p, answer=%p\n", sockfd, answer); return -1; } memset(read_buffer, '\0', sizeof(read_buffer)); do { bytes_read = recv(sockfd, &read_buffer[total], sizeof(read_buffer), 0); total += bytes_read; } while (bytes_read > 0 && total < sizeof(read_buffer) - 1); /* Parse answer */ memset(answer, '\0', 1); ret = 0; ret = read_packet_content(read_buffer, answer); /* If answer was IPv4 address mapped to IPv6 revert to IPv4 format*/ pton_ret = inet_pton(AF_INET6, answer, &ipv6); if (pton_ret && IN6_IS_ADDR_V4MAPPED(&ipv6)) { IPV6_TO_IPV4_MAP(&ipv6, &ipv4); sprintf(answer, "%s", inet_ntoa(ipv4)); } out_err: return ret; }
u8 *hip_create_keymat_buffer(char *kij, size_t kij_len, size_t hash_len, struct in6_addr *smaller_hit, struct in6_addr *bigger_hit, uint64_t I, uint64_t J) { u8 *buffer = NULL, *cur = NULL; size_t requiredmem; HIP_DEBUG("\n"); /* 2*sizeof(uint64_t) added to take care of I and J. */ if (2 * sizeof(struct in6_addr) < hash_len) requiredmem = kij_len + hash_len + sizeof(u8) + 2*sizeof(uint64_t); else requiredmem = kij_len + 2 * sizeof(struct in6_addr) + sizeof(u8) + 2*sizeof(uint64_t); buffer = (u8 *)HIP_MALLOC(requiredmem, GFP_KERNEL); if (!buffer) { HIP_ERROR("Out of memory\n"); return buffer; } cur = buffer; memcpy(cur, kij, kij_len); cur += kij_len; memcpy(cur, (u8 *)smaller_hit, sizeof(struct in6_addr)); cur += sizeof(struct in6_addr); memcpy(cur,(u8 *)bigger_hit, sizeof(struct in6_addr)); cur += sizeof(struct in6_addr); memcpy(cur, &I, sizeof(uint64_t)); // XX CHECK: network byte order? cur += sizeof(uint64_t); memcpy(cur, &J, sizeof(uint64_t)); // XX CHECK: network byte order? cur += sizeof(uint64_t); *(cur) = 1; cur += sizeof(u8); _HIP_HEXDUMP("beginning of keymat", buffer, cur - buffer); return buffer; }
/** * Convert the opaque value in the CHALLENGE_REQUEST to the seed value I of a * HIP puzzle. * * The opaque value plays a dual role in a CHALLENGE_REQUEST: * i) it is a challenge that needs to be echoed back by the responder and * ii) it is used to derive the seed value for a cryptographic puzzle. The * puzzle is defined in RFC5201. * * @param opaque the nonce (challenge) in the CHALLENGE_REQUEST * @param opaque_len the length of the nonce * @param puzzle_value the puzzle value generated from the nonce * @return zero on success, -1 in case of an error */ int hip_midauth_puzzle_seed(const uint8_t opaque[], const unsigned int opaque_len, uint8_t puzzle_value[PUZZLE_LENGTH]) { unsigned char sha_digest[SHA_DIGEST_LENGTH]; HIP_ASSERT(puzzle_value != NULL); // the hashed opaque field is used as puzzle seed if (hip_build_digest(HIP_DIGEST_SHA1, opaque, opaque_len, sha_digest)) { HIP_ERROR("Building of SHA1 random seed I failed\n"); return -1; } memcpy(puzzle_value, &sha_digest[SHA_DIGEST_LENGTH - PUZZLE_LENGTH], PUZZLE_LENGTH); return 0; }
/** * Print a socket address structure. * * @param file source file. * @param line the line of the debug call in the source file * @param function the name of function where the debug call is located * @param prefix the prefix string will printed before the sockaddr * @param sockaddr pointer to the sockaddr to be printed * * @note Do not call this function from the outside of the debug module, use the * HIP_DEBUG_SOCKADDR macro instead. * @note Currently this function supports only INET and INET6 addresses. */ void hip_print_sockaddr(UNUSED const char *file, UNUSED int line, UNUSED const char *function, const char *prefix, const struct sockaddr *sockaddr) { const char *default_str = "<unknown>"; int maxlen; const void *addr; int family = sockaddr->sa_family; char addr_str[INET6_ADDRSTRLEN + 1]; switch (family) { case AF_INET: maxlen = INET_ADDRSTRLEN; addr = &((const struct sockaddr_in *) sockaddr)->sin_addr; break; case AF_INET6: maxlen = INET6_ADDRSTRLEN; addr = &((const struct sockaddr_in6 *) sockaddr)->sin6_addr; break; default: maxlen = 0; } if (maxlen == 0) { memcpy(addr_str, default_str, strlen(default_str) + 1); } else { if (!inet_ntop(family, addr, addr_str, maxlen)) { HIP_ERROR("inet_ntop"); return; } } if (prefix) { HIP_DEBUG("%s: %s\n", prefix, addr_str); } else { HIP_DEBUG("%s\n", addr_str); } }
/** * allocate and initialize a big enough key material buffer for * drawing symmetric keys for HIP and ESP * * @param kij the diffie hellman session key * @param kij_len the length of kij in bytes * @param hash_len the length of the used hash * @param smaller_hit smaller HIT * @param bigger_hit bigger HIT * @param I the I value from the puzzle * @param J the J value from the puzzle * @return the allocated buffer (caller deallocates) or NULL on failure */ static uint8_t *hip_create_keymat_buffer(char *kij, size_t kij_len, size_t hash_len, struct in6_addr *smaller_hit, struct in6_addr *bigger_hit, const uint8_t I[PUZZLE_LENGTH], const uint8_t J[PUZZLE_LENGTH]) { uint8_t *buffer = NULL, *cur = NULL; size_t requiredmem; if (2 * sizeof(struct in6_addr) < hash_len) { requiredmem = kij_len + hash_len + sizeof(uint8_t) + 2 * PUZZLE_LENGTH; } else { requiredmem = kij_len + 2 * sizeof(struct in6_addr) + sizeof(uint8_t) + 2 * PUZZLE_LENGTH; } buffer = malloc(requiredmem); if (!buffer) { HIP_ERROR("Out of memory\n"); return buffer; } cur = buffer; memcpy(cur, kij, kij_len); cur += kij_len; memcpy(cur, (uint8_t *) smaller_hit, sizeof(struct in6_addr)); cur += sizeof(struct in6_addr); memcpy(cur, (uint8_t *) bigger_hit, sizeof(struct in6_addr)); cur += sizeof(struct in6_addr); memcpy(cur, I, PUZZLE_LENGTH); cur += PUZZLE_LENGTH; memcpy(cur, J, PUZZLE_LENGTH); cur += PUZZLE_LENGTH; *(cur) = 1; cur += sizeof(uint8_t); return buffer; }
int hip_send_recv_daemon_info(struct hip_common *msg, int send_only, int opt_socket) { int hip_user_sock = 0, err = 0, n, len; struct sockaddr_in6 addr; if (!send_only) return hip_send_recv_daemon_info_internal(msg, opt_socket); if (opt_socket) { hip_user_sock = opt_socket; } else { HIP_IFE(((hip_user_sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0), -1); memset(&addr, 0, sizeof(addr)); addr.sin6_family = AF_INET6; addr.sin6_addr = in6addr_loopback; HIP_IFEL(hip_daemon_bind_socket(hip_user_sock, (struct sockaddr *) &addr), -1, "bind failed\n"); HIP_IFEL(hip_daemon_connect(hip_user_sock), -1, "connect failed\n"); } len = hip_get_msg_total_len(msg); n = send(hip_user_sock, msg, len, 0); if (n < len) { HIP_ERROR("Could not send message to daemon.\n"); err = -1; goto out_err; } out_err: if (!opt_socket && hip_user_sock) close(hip_user_sock); return err; }
int main(int argc,char *argv[]) { struct ifaddrs *g_ifaces = NULL, *g_iface; struct if_nameindex *i_ifaces = NULL, *i_iface; int err = 0; char *default_str = "<unknown>"; char addr_str[INET6_ADDRSTRLEN+1]; /* Segfault? Alloc this dynamically?x */ /* getifaddrs */ err = getifaddrs(&g_ifaces); if (err) { HIP_ERROR("getifaddr failed\n"); goto out; } printf("===getifaddrs===\n"); for (g_iface = g_ifaces; g_iface; g_iface = g_iface->ifa_next) { sa_family_t family = g_iface->ifa_addr->sa_family; fprintf(stderr, "name: %s, family: %d, address ", g_iface->ifa_name, family); HIP_DEBUG_SOCKADDR(NULL, g_iface->ifa_addr); } /* if_nameindex */ printf("===nameindex===\n"); i_ifaces = if_nameindex(); for (i_iface = i_ifaces; i_iface->if_index; i_iface++) { fprintf(stderr, "name: %s index: %d\n", i_iface->if_name, i_iface->if_index); } out: if (g_ifaces) freeifaddrs(g_ifaces); if (i_ifaces) if_freenameindex(i_ifaces); }
/** * Register a maintenance function. All maintenance functions are called during * the periodic maintenance cycle. * * @param maint_function Pointer to the maintenance function. * @param priority Priority of the maintenance function. * * @return Success = 0 * Error = -1 * */ int hip_register_maint_function(int (*maint_function)(void), const uint16_t priority) { int err = 0; struct maint_function *new_entry = NULL; HIP_IFEL(!(new_entry = malloc(sizeof(struct maint_function))), -1, "Error on allocating memory for a maintenance function entry.\n"); new_entry->priority = priority; new_entry->func_ptr = maint_function; hip_maintenance_functions = lmod_register_function(hip_maintenance_functions, new_entry, priority); if (!hip_maintenance_functions) { HIP_ERROR("Error on registering a maintenance function.\n"); err = -1; } out_err: return err; }
/** * Finds out how much data is coming from a socket * * @param socket a file descriptor. * @param encap_hdr_size udp etc header size * @param timeout -1 for blocking sockets, 0 or positive nonblocking * @return Number of bytes received on success or a negative error value on * error. */ int hip_peek_recv_total_len(int socket, int encap_hdr_size, unsigned long timeout) { int bytes = 0, err = 0, flags = MSG_PEEK; unsigned long timeout_left = timeout; int hdr_size = encap_hdr_size + sizeof(struct hip_common); char *msg = NULL; hip_common_t *hip_hdr = NULL; struct timespec ts; ts.tv_sec = 0; ts.tv_nsec = 100000000; /* We're using system call here add thus reseting errno. */ errno = 0; msg = (char *)malloc(hdr_size); HIP_IFEL(!msg, -ENOMEM, "Error allocating memory.\n"); /* Make sure the socket does not block (bug id 806) */ if (timeout >= 0) flags |= MSG_DONTWAIT; do { errno = 0; nanosleep(&ts, NULL); bytes = recv(socket, msg, hdr_size, flags); timeout_left -= ts.tv_nsec; _HIP_DEBUG("tol=%ld, ts=%ld, bytes=%d errno=%d\n", timeout_left, ts.tv_nsec, bytes, errno); } while (timeout_left > 0 && errno == EAGAIN && bytes < 0); if(bytes < 0) { HIP_ERROR("recv() peek error (is hipd running?)\n"); err = -EAGAIN; goto out_err; } else if (bytes < hdr_size) { HIP_ERROR("Packet payload is smaller than HIP header. Dropping.\n"); /* Read and discard the datagram */ recv(socket, msg, 0, 0); err = -bytes; goto out_err; } hip_hdr = (struct hip_common *) (msg + encap_hdr_size); bytes = hip_get_msg_total_len(hip_hdr); if(bytes == 0) { HIP_ERROR("HIP message is of zero length. Dropping.\n"); recv(socket, msg, 0, 0); err = -EBADMSG; errno = EBADMSG; goto out_err; } /* The maximum possible length value is equal to HIP_MAX_PACKET. if(bytes > HIP_MAX_PACKET) { HIP_ERROR("HIP message max length exceeded. Dropping.\n"); recv(socket, msg, 0, 0); err = -EMSGSIZE; errno = EMSGSIZE; goto out_err; } */ bytes += encap_hdr_size; out_err: if (msg != NULL) free(msg); if (err) return err; return bytes; }
/** * Translate and reinject an incoming packet back to the networking stack. * Supports TCP, UDP and ICMP. LSI code uses this to translate * the HITs from an incoming packet to the corresponding LSIs. Also, * the system-based opportunistic mode uses this to translate the HITs of * an incoming packet to an IPv4 or IPv6 address. * * @param src_hit source HIT of the packet * @param dst_hit destination HIT of the packet * @param msg a pointer to the transport layer header of the packet * @param len the length of the packet in bytes * @param proto the transport layer protocol of the packet * @param ttl new ttl value for the transformed packet * * @return zero on success and non-zero on error */ int hip_firewall_send_incoming_pkt(const struct in6_addr *src_hit, const struct in6_addr *dst_hit, uint8_t *msg, uint16_t len, int proto, int ttl) { int err = 0, sent, sa_size; int firewall_raw_sock = 0, is_ipv6 = 0, on = 1; struct ip *iphdr = NULL; struct udphdr *udp = NULL; struct tcphdr *tcp = NULL; struct icmphdr *icmp = NULL; struct sockaddr_storage src = { 0 }, dst = { 0 }; struct sockaddr_in6 *sock_src6 = NULL, *sock_dst6 = NULL; struct sockaddr_in *sock_src4 = NULL, *sock_dst4 = NULL; struct in6_addr any = IN6ADDR_ANY_INIT; HIP_ASSERT(src_hit != NULL && dst_hit != NULL); sock_src4 = (struct sockaddr_in *) &src; sock_dst4 = (struct sockaddr_in *) &dst; sock_src6 = (struct sockaddr_in6 *) &src; sock_dst6 = (struct sockaddr_in6 *) &dst; if (IN6_IS_ADDR_V4MAPPED(src_hit)) { sock_src4->sin_family = AF_INET; sock_dst4->sin_family = AF_INET; IPV6_TO_IPV4_MAP(src_hit, &sock_src4->sin_addr); IPV6_TO_IPV4_MAP(dst_hit, &sock_dst4->sin_addr); sa_size = sizeof(struct sockaddr_in); HIP_DEBUG_LSI("src4 addr ", &sock_src4->sin_addr); HIP_DEBUG_LSI("dst4 addr ", &sock_dst4->sin_addr); } else { sock_src6->sin6_family = AF_INET6; ipv6_addr_copy(&sock_src6->sin6_addr, src_hit); sock_dst6->sin6_family = AF_INET6; ipv6_addr_copy(&sock_dst6->sin6_addr, dst_hit); sa_size = sizeof(struct sockaddr_in6); is_ipv6 = 1; } switch (proto) { case IPPROTO_UDP: if (is_ipv6) { HIP_DEBUG(" IPPROTO_UDP v6\n"); firewall_raw_sock = firewall_raw_sock_udp_v6; ((struct udphdr *) msg)->check = ipv6_checksum(IPPROTO_UDP, &sock_src6->sin6_addr, &sock_dst6->sin6_addr, msg, len); } else { HIP_DEBUG(" IPPROTO_UDP v4\n"); firewall_raw_sock = firewall_raw_sock_udp_v4; udp = (struct udphdr *) msg; sa_size = sizeof(struct sockaddr_in); udp->check = htons(0); udp->check = ipv4_checksum(IPPROTO_UDP, (uint8_t *) &sock_src4->sin_addr, (uint8_t *) &sock_dst4->sin_addr, (uint8_t *) udp, len); memmove(msg + sizeof(struct ip), udp, len); } break; case IPPROTO_TCP: tcp = (struct tcphdr *) msg; tcp->check = htons(0); if (is_ipv6) { HIP_DEBUG(" IPPROTO_TCP v6\n"); firewall_raw_sock = firewall_raw_sock_tcp_v6; tcp->check = ipv6_checksum(IPPROTO_TCP, &sock_src6->sin6_addr, &sock_dst6->sin6_addr, msg, len); } else { HIP_DEBUG(" IPPROTO_TCP v4\n"); firewall_raw_sock = firewall_raw_sock_tcp_v4; tcp->check = ipv4_checksum(IPPROTO_TCP, (uint8_t *) &sock_src4->sin_addr, (uint8_t *) &sock_dst4->sin_addr, (uint8_t *) tcp, len); memmove(msg + sizeof(struct ip), tcp, len); } break; case IPPROTO_ICMP: firewall_raw_sock = firewall_raw_sock_icmp_v4; icmp = (struct icmphdr *) msg; icmp->checksum = htons(0); icmp->checksum = inchksum(icmp, len); memmove(msg + sizeof(struct ip), icmp, len); break; case IPPROTO_ICMPV6: goto not_sending; break; default: HIP_ERROR("No protocol family found\n"); break; } if (!is_ipv6) { iphdr = (struct ip *) msg; iphdr->ip_v = 4; iphdr->ip_hl = sizeof(struct ip) >> 2; iphdr->ip_tos = 0; iphdr->ip_len = len + iphdr->ip_hl * 4; iphdr->ip_id = htons(0); iphdr->ip_off = 0; iphdr->ip_ttl = ttl; iphdr->ip_p = proto; iphdr->ip_src = sock_src4->sin_addr; iphdr->ip_dst = sock_dst4->sin_addr; iphdr->ip_sum = htons(0); /* @todo: move the socket option to fw initialization */ if (setsockopt(firewall_raw_sock, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on))) { HIP_IFEL(err, -1, "setsockopt IP_HDRINCL ERROR\n"); } sent = sendto(firewall_raw_sock, iphdr, iphdr->ip_len, 0, (struct sockaddr *) &dst, sa_size); if (sent != (int) (len + sizeof(struct ip))) { HIP_ERROR("Could not send the all requested" \ " data (%d/%d)\n", sent, iphdr->ip_len); } else { HIP_DEBUG("sent=%d/%d \n", sent, (len + sizeof(struct ip))); HIP_DEBUG("Packet sent ok\n"); } }
/** * connect_dht_gateway - Connects to given v6 gateway * @param sockfd * @param addrinfo Address to connect to * @param blocking 1 for blocking connect 0 for nonblocking * * @return Returns 0 on success -1 otherwise, if nonblocking can return EINPRGORESS */ int connect_dht_gateway(int sockfd, struct addrinfo * gateway, int blocking){ int flags = 0, error = 0; struct sockaddr_in *sa_v4; struct sockaddr_in6 *sa_v6; struct sigaction act, oact; act.sa_handler = connect_alarm; sigemptyset(&act.sa_mask); act.sa_flags = 0; if(gateway == NULL){ HIP_ERROR("No OpenDHT Serving Gateway Address.\n"); return(-1); } if(blocking == 0) goto unblock; // blocking connect if(sigaction(SIGALRM, &act, &oact) < 0){ HIP_DEBUG("Signal error before OpenDHT connect, " "connecting without alarm\n"); error = connect(sockfd, gateway->ai_addr, gateway->ai_addrlen); }else { HIP_DEBUG("Connecting to OpenDHT with alarm\n"); if (alarm(DHT_CONNECT_TIMEOUT) != 0) HIP_DEBUG("Alarm was already set, connecting without\n"); error = connect(sockfd, gateway->ai_addr, gateway->ai_addrlen); alarm(0); if (sigaction(SIGALRM, &oact, &act) <0 ) HIP_DEBUG("Signal error after OpenDHT connect\n"); } if(error < 0){ HIP_PERROR("OpenDHT connect:"); if (errno == EINTR) HIP_DEBUG("Connect to OpenDHT timedout\n"); return(-1); }else{ if(gateway->ai_family == AF_INET){ sa_v4 = (struct sockaddr_in *)gateway->ai_addr; HIP_DEBUG_INADDR("Connected to OpenDHT v4 gateway", &(sa_v4->sin_addr)); } else if(gateway->ai_family == AF_INET6){ sa_v6 = (struct sockaddr_in6 *)gateway->ai_addr; HIP_DEBUG_IN6ADDR("Connected to OpenDHT v6 gateway", &(sa_v6->sin6_addr)); } else{ HIP_DEBUG("Wrong address family for OPENDHT gateway %d\n", gateway->ai_family); } return(0); } unblock: // unblocking connect flags = fcntl(sockfd, F_GETFL, 0); fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); if(gateway->ai_family == AF_INET){ sa_v4 = (struct sockaddr_in *)gateway->ai_addr; HIP_DEBUG_INADDR("Connecting to OpenDHT v4 gateway", &(sa_v4->sin_addr)); } else if(gateway->ai_family == AF_INET6){ sa_v6 = (struct sockaddr_in6 *)gateway->ai_addr; HIP_DEBUG_IN6ADDR("Connecting to OpenDHT v6 gateway", &(sa_v6->sin6_addr)); } else{ HIP_DEBUG("Wrong address family for OPENDHT gateway %d\n", gateway->ai_family); } if(connect(sockfd, gateway->ai_addr, gateway->ai_addrlen) < 0){ if (errno == EINPROGRESS) return(EINPROGRESS); else{ HIP_PERROR("OpenDHT connect:"); return(-1); } }else{ // connect ok return(0); } }
/** This thread keeps the HIP daemon connection alive. */ void *connhipd_thread(void *data) { /* Variables. */ int err = 0, n, len, ret, max_fd; struct sockaddr_in6 agent_addr; struct hip_common *msg = (struct hip_common *)data; socklen_t alen; fd_set read_fdset; struct timeval tv; HIP_DEBUG("Waiting messages...\n"); /* Start handling. */ hip_agent_thread_started = 1; while (hip_agent_thread_started) { FD_ZERO(&read_fdset); FD_SET(hip_agent_sock, &read_fdset); max_fd = hip_agent_sock; tv.tv_sec = 1; tv.tv_usec = 0; if (hip_agent_connected < 1) { /* Test connection. */ //HIP_IFEL(hip_agent_connected < -60, -1, "Could not connect to daemon.\n"); //HIP_DEBUG("Pinging daemon...\n"); hip_build_user_hdr(msg, SO_HIP_AGENT_PING, 0); n = hip_send_recv_daemon_info((char *)msg, 1, hip_agent_sock); //if (n < 0) HIP_DEBUG("Could not send ping to daemon, waiting.\n"); hip_agent_connected--; } /* Wait for incoming packets. */ if (select(max_fd + 1, &read_fdset, NULL,NULL, &tv) == -1) { HIP_ERROR("select() error: %s.\n", strerror(errno)); err = -1; goto out_err; } if (!hip_agent_thread_started) continue; if (!FD_ISSET(hip_agent_sock, &read_fdset)) continue; memset(&agent_addr, 0, sizeof(agent_addr)); alen = sizeof(agent_addr); n = recvfrom(hip_agent_sock, msg, sizeof(struct hip_common), MSG_PEEK, (struct sockaddr *)&agent_addr, &alen); if (n < 0) { HIP_ERROR("Error receiving message header from daemon.\n"); err = -1; goto out_err; } // HIP_DEBUG("Header received successfully\n"); alen = sizeof(agent_addr); len = hip_get_msg_total_len(msg); n = recvfrom(hip_agent_sock, msg, len, 0, (struct sockaddr *)&agent_addr, &alen); if (n < 0) { HIP_ERROR("Error receiving message parameters from daemon.\n"); err = -1; goto out_err; } //HIP_DEBUG("Received message from daemon (%d bytes)\n", n); //HIP_ASSERT(n == len); if (n != len) { HIP_ERROR("Received packet length and HIP msg len dont match %d != %d!!!\n", n, len); continue; } if (agent_addr.sin6_port != ntohs(HIP_DAEMON_LOCAL_PORT)) { HIP_DEBUG("Drop, message not from hipd"); continue; } connhipd_handle_msg(msg, &agent_addr); } out_err: /* Send quit message to daemon. */ hip_build_user_hdr(msg, SO_HIP_AGENT_QUIT, 0); n = hip_send_recv_daemon_info((char *)msg, 1, hip_agent_sock); if (n < 0) HIP_ERROR("Could not send quit message to daemon.\n"); if (hip_agent_sock) close(hip_agent_sock); if (msg != NULL) HIP_FREE(msg); hip_agent_thread_started = 0; agent_exit(); HIP_DEBUG("Connection thread exit.\n"); /* This function cannot have a returning value */ /*return (err);*/ }