/** * Update firewall on host association state. Currently used by the * LSI mode in the firewall. * * @param action HIP_MSG_FW_UPDATE_DB or HIP_MSG_FW_BEX_DONE * @param hit_s optional source HIT * @param hit_r optional destination HIT * * @return zero on success or negative on failure */ int hip_firewall_set_bex_data(int action, struct in6_addr *hit_s, struct in6_addr *hit_r) { struct hip_common *msg = NULL; int err = 0, n = 0, r_is_our; if (!hip_get_firewall_status()) { goto out_err; } /* Makes sure that the hits are sent always in the same order */ r_is_our = hip_hidb_hit_is_our(hit_r); HIP_IFEL(!(msg = malloc(HIP_MAX_PACKET)), -1, "alloc\n"); hip_msg_init(msg); HIP_IFEL(hip_build_user_hdr(msg, action, 0), -1, "Build hdr failed\n"); HIP_IFEL(hip_build_param_contents(msg, r_is_our ? hit_s : hit_r, HIP_PARAM_HIT, sizeof(struct in6_addr)), -1, "build param contents failed\n"); HIP_IFEL(hip_build_param_contents(msg, r_is_our ? hit_r : hit_s, HIP_PARAM_HIT, sizeof(struct in6_addr)), -1, "build param contents failed\n"); n = sendto(hip_firewall_sock_lsi_fd, (char *) msg, hip_get_msg_total_len(msg), 0, (struct sockaddr *) &hip_firewall_addr, sizeof(struct sockaddr_in6)); HIP_IFEL(n < 0, -1, "Send to firewall failed. str errno %s\n", strerror(errno)); HIP_DEBUG("BEX DATA Send to firewall OK.\n"); out_err: free(msg); return err; }
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; }
/** Handle message from agent socket. */ int connhipd_handle_msg(struct hip_common *msg, struct sockaddr_un *addr) { /* Variables. */ struct hip_tlv_common *param = NULL, *param2 = NULL; struct hip_common *emsg; hip_hdr_type_t type; HIT_Remote hit, *r; HIT_Local *l; socklen_t alen; struct in6_addr *lhit, *rhit; int err = 0, ret, n, direction, check; char chit[128], *type_s; struct in6_addr hitr ; type = hip_get_msg_type(msg); if (type == SO_HIP_AGENT_PING_REPLY) { HIP_DEBUG("Received ping reply from daemon. Connection to daemon established.\n"); gui_set_info(lang_get("gui-info-000")); hip_agent_connected = 1; } else if (type == SO_HIP_SET_NAT_ON) { gui_update_nat(1); HIP_DEBUG("NAT extensions on.\n"); } else if (type == SO_HIP_SET_NAT_OFF) { gui_update_nat(0); HIP_DEBUG("NAT extensions off.\n"); } else if (type == SO_HIP_DAEMON_QUIT) { HIP_DEBUG("Daemon quit. Waiting daemon to wake up again...\n"); gui_set_info(lang_get("gui-info-001")); hip_agent_connected = 0; } else if (type == SO_HIP_ADD_DB_HI) { HIP_DEBUG("Message received successfully from daemon with type" " HIP_ADD_DB_HI (%d).\n", type); n = 0; while((param = hip_get_next_param(msg, param))) { if (hip_get_param_type(param) == HIP_PARAM_HIT) { lhit = (struct in6_addr *)hip_get_param_contents_direct(param); HIP_HEXDUMP("Adding local HIT:", lhit, 16); print_hit_to_buffer(chit, lhit); hit_db_add_local(chit, lhit); n++; } } } else if (type == SO_HIP_UPDATE_HIU) { n = 0; gui_hiu_clear(); while((param = hip_get_next_param(msg, param))) { /*param2 = hip_get_next_param(msg, param); if (param2 == NULL) break;*/ if (hip_get_param_type(param) == HIP_PARAM_HIT)/* && hip_get_param_type(param2) == HIP_PARAM_HIT)*/ { rhit = (struct in6_addr *)hip_get_param_contents_direct(param); //lhit = hip_get_param_contents_direct(param2); r = hit_db_find(NULL, rhit); if (r) { gui_hiu_add(r); n++; } } } gui_hiu_count(n); } else if (type == HIP_I1 || type == HIP_R1) { NAMECPY(hit.name, ""); URLCPY(hit.url, "<notset>"); URLCPY(hit.port, ""); HIP_DEBUG("Message from daemon, %d bytes.\n", hip_get_msg_total_len(msg)); /* Get original message, which is encapsulated inside received one. */ emsg = (struct hip_common *)hip_get_param_contents(msg, HIP_PARAM_ENCAPS_MSG); HIP_IFEL(!emsg, -1, "Could not get msg parameter!\n"); HIP_HEXDUMP("msg->hits: ", &emsg->hits, 16); HIP_HEXDUMP("msg->hitr: ", &emsg->hitr, 16); /* Find out, which of the HITs in the message is local HIT. */ l = hit_db_find_local(NULL, &emsg->hits); if (!l) { l = hit_db_find_local(NULL, &emsg->hitr); if (l) { memcpy(&hit.hit, &emsg->hits, sizeof(hit.hit)); } HIP_IFEL(!l, -1, "Did not find local HIT for message!\n"); } else { memcpy(&hit.hit, &emsg->hitr, sizeof(hit.hit)); } HIP_DEBUG("Received %s %s from daemon.\n", "incoming", type == HIP_I1 ? "I1" : "R1"); /* Check the remote HIT from database. */ if (l) { memcpy(&hitr,&hit.hit, sizeof(struct in6_addr)); ret = check_hit(&hit, 0); /*Send our hits -- peer hit to daemon*/ if (ret == 1) ret = 0; /*hit already exist in the database and is accepted so no need to send it to daemon*/ else if (ret == 0) connhipd_send_hitdata_to_daemon (msg, &hitr, &hit.g->l->lhit) ; /* Reset local HIT, if outgoing I1. */ /*HIP_HEXDUMP("Old local HIT: ", &msg->hits, 16); HIP_HEXDUMP("New local HIT: ", &hit.g->l->lhit, 16); HIP_HEXDUMP("Old remote HIT: ", &msg->hitr, 16); HIP_HEXDUMP("New remote HIT: ", &hit.hit, 16);*/ } /* If neither HIT in message was local HIT, then drop the packet! */ else { HIP_DEBUG("Failed to find local HIT from database for packet." " Rejecting packet automatically.\n"); HIP_HEXDUMP("msg->hits: ", &msg->hits, 16); HIP_HEXDUMP("msg->hitr: ", &msg->hits, 16); ret = -1; } /* Now either reject or accept the packet, according to previous results. */ if (ret == 0) { HIP_DEBUG("Message accepted, sending back to daemon, %d bytes.\n", hip_get_msg_total_len(msg)); n = hip_send_recv_daemon_info((char *)msg, 1, hip_agent_sock); HIP_IFEL(n < 0, -1, "Could not send message back to daemon" " (%d: %s).\n", errno, strerror(errno)); HIP_DEBUG("Reply sent successfully.\n"); } else if (type == HIP_R1) { HIP_DEBUG("Message rejected.\n"); n = 1; HIP_IFE(hip_build_param_contents(msg, &n, HIP_PARAM_AGENT_REJECT, sizeof(n)), -1); n = hip_send_recv_daemon_info((char *)msg, 1, hip_agent_sock); HIP_IFEL(n < 0, -1, "Could not send message back to daemon" " (%d: %s).\n", errno, strerror(errno)); HIP_DEBUG("Reply sent successfully.\n"); } else { HIP_DEBUG("Message rejected.\n"); } } out_err: // HIP_DEBUG("Message handled.\n"); return (err); }
/** 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);*/ }
/** * 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; }
/* * Don't call this function directly. Use hip_send_recv_daemon_info instead */ int hip_send_recv_daemon_info_internal(struct hip_common *msg, int opt_socket) { int hip_user_sock = 0, err = 0, n = 0, len = 0; struct sockaddr_in6 addr; uint8_t msg_type_old, msg_type_new; msg_type_old = hip_get_msg_type(msg); // We're using system call here and thus reseting errno. errno = 0; if (opt_socket) { hip_user_sock = opt_socket; } else { HIP_IFE(((hip_user_sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0), EHIP); 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"); /* Connect to hipd. Otherwise e.g. "hipconf get ha all" blocks when hipd is not running. */ HIP_IFEL(hip_daemon_connect(hip_user_sock), -1, "connect failed\n"); } if ((len = hip_get_msg_total_len(msg)) < 0) { err = -EBADMSG; goto out_err; } /* Require a response from hipd */ hip_set_msg_response(msg, 1); n = hip_sendto_hipd(hip_user_sock, msg, len); if (n < len) { HIP_ERROR("Could not send message to daemon.\n"); err = -ECOMM; goto out_err; } HIP_DEBUG("Waiting to receive daemon info.\n"); if((len = hip_peek_recv_total_len(hip_user_sock, 0, HIP_DEFAULT_MSG_TIMEOUT)) < 0) { err = len; goto out_err; } n = recv(hip_user_sock, msg, len, 0); /* You have a message synchronization problem if you see this error. */ msg_type_new = hip_get_msg_type(msg); HIP_IFEL((msg_type_new != msg_type_old), -1, "Message sync problem. Expected %d, got %d\n", msg_type_old, msg_type_new); HIP_DEBUG("%d bytes received from HIP daemon\n", n); if (n == 0) { HIP_INFO("The HIP daemon has performed an "\ "orderly shutdown.\n"); // Note. This is not an error condition, thus we return zero. goto out_err; } else if(n < sizeof(struct hip_common)) { HIP_ERROR("Could not receive message from daemon.\n"); goto out_err; } if (hip_get_msg_err(msg)) { HIP_ERROR("HIP message contained an error.\n"); err = -EHIP; } _HIP_DEBUG("Message received successfully\n"); out_err: if (!opt_socket && hip_user_sock) close(hip_user_sock); return err; }
static int send_raw_from_one_src(const struct in6_addr *local_addr, const struct in6_addr *peer_addr, const in_port_t src_port, const in_port_t dst_port, struct hip_common *msg) { int err = 0, sa_size, sent, len = 0, dupl, try_again, udp = 0; struct sockaddr_storage src, dst; int src_is_ipv4 = 0, dst_is_ipv4 = 0, memmoved = 0; struct sockaddr_in6 *src6 = NULL, *dst6 = NULL; struct sockaddr_in *src4 = NULL, *dst4 = NULL; struct in6_addr my_addr; /* Points either to v4 or v6 raw sock */ int hipfw_raw_sock_output = 0; /* Verify the existence of obligatory parameters. */ HIP_ASSERT(peer_addr != NULL && msg != NULL); HIP_DEBUG("Sending %s packet\n", hip_message_type_name(hip_get_msg_type(msg))); HIP_DEBUG_IN6ADDR("hip_send_raw(): local_addr", local_addr); HIP_DEBUG_IN6ADDR("hip_send_raw(): peer_addr", peer_addr); HIP_DEBUG("Source port=%d, destination port=%d\n", src_port, dst_port); HIP_DUMP_MSG(msg); //check msg length if (!hip_check_network_msg_len(msg)) { err = -EMSGSIZE; HIP_ERROR("bad msg len %d\n", hip_get_msg_total_len(msg)); goto out_err; } dst_is_ipv4 = IN6_IS_ADDR_V4MAPPED(peer_addr); len = hip_get_msg_total_len(msg); /* Some convinient short-hands to avoid too much casting (could be * an union as well) */ src6 = (struct sockaddr_in6 *) &src; dst6 = (struct sockaddr_in6 *) &dst; src4 = (struct sockaddr_in *) &src; dst4 = (struct sockaddr_in *) &dst; memset(&src, 0, sizeof(src)); memset(&dst, 0, sizeof(dst)); if (dst_port && dst_is_ipv4) { HIP_DEBUG("Using IPv4 UDP socket\n"); hipfw_raw_sock_output = hipfw_nat_sock_output_udp; sa_size = sizeof(struct sockaddr_in); udp = 1; } else if (dst_is_ipv4) { HIP_DEBUG("Using IPv4 raw socket\n"); //hipfw_raw_sock_output = hipfw_raw_sock_output_v4; //sa_size = sizeof(struct sockaddr_in); } else { HIP_DEBUG("Using IPv6 raw socket\n"); //hipfw_raw_sock_output = hipfw_raw_sock_output_v6; //sa_size = sizeof(struct sockaddr_in6); } if (local_addr) { HIP_DEBUG("local address given\n"); memcpy(&my_addr, local_addr, sizeof(struct in6_addr)); } else { HIP_DEBUG("no local address, selecting one\n"); HIP_IFEL(select_source_address(&my_addr, peer_addr), -1, "Cannot find source address\n"); } src_is_ipv4 = IN6_IS_ADDR_V4MAPPED(&my_addr); if (src_is_ipv4) { IPV6_TO_IPV4_MAP(&my_addr, &src4->sin_addr); src4->sin_family = AF_INET; HIP_DEBUG_INADDR("src4", &src4->sin_addr); } else { memcpy(&src6->sin6_addr, &my_addr, sizeof(struct in6_addr)); src6->sin6_family = AF_INET6; HIP_DEBUG_IN6ADDR("src6", &src6->sin6_addr); } if (dst_is_ipv4) { IPV6_TO_IPV4_MAP(peer_addr, &dst4->sin_addr); dst4->sin_family = AF_INET; HIP_DEBUG_INADDR("dst4", &dst4->sin_addr); } else { memcpy(&dst6->sin6_addr, peer_addr, sizeof(struct in6_addr)); dst6->sin6_family = AF_INET6; HIP_DEBUG_IN6ADDR("dst6", &dst6->sin6_addr); } if (src6->sin6_family != dst6->sin6_family) { /* @todo: Check if this may cause any trouble. * It happens every time we send update packet that contains few locators in msg, one is * the IPv4 address of the source, another is IPv6 address of the source. But even if one of * them is ok to send raw IPvX to IPvX raw packet, another one cause the trouble, and all * updates are dropped. by Andrey "laser". * */ err = -1; HIP_ERROR("Source and destination address families differ\n"); goto out_err; } hip_zero_msg_checksum(msg); if (!udp) { msg->checksum = hip_checksum_packet((char *) msg, (struct sockaddr *) &src, (struct sockaddr *) &dst); } /* Handover may cause e.g. on-link duplicate address detection * which may cause bind to fail. */ HIP_IFEL(bind(hipfw_raw_sock_output, (struct sockaddr *) &src, sa_size), -1, "Binding to raw sock failed\n"); /* For some reason, neither sendmsg or send (with bind+connect) * do not seem to work properly. Thus, we use just sendto() */ len = hip_get_msg_total_len(msg); if (udp) { struct udphdr *uh = (struct udphdr *) msg; /* Insert 32 bits of zero bytes between UDP and HIP */ memmove(((char *) msg) + HIP_UDP_ZERO_BYTES_LEN + sizeof(struct udphdr), msg, len); memset(((char *) msg), 0, HIP_UDP_ZERO_BYTES_LEN + sizeof(struct udphdr)); len += HIP_UDP_ZERO_BYTES_LEN + sizeof(struct udphdr); uh->source = htons(src_port); uh->dest = htons(dst_port); uh->len = htons(len); uh->check = 0; memmoved = 1; } for (dupl = 0; dupl < 1; dupl++) { for (try_again = 0; try_again < 2; try_again++) { sent = sendto(hipfw_raw_sock_output, msg, len, 0, (struct sockaddr *) &dst, sa_size); if (sent != len) { HIP_ERROR("Could not send the all requested" \ " data (%d/%d)\n", sent, len); HIP_DEBUG("strerror %s\n", strerror(errno)); sleep(2); } else { HIP_DEBUG("sent=%d/%d ipv4=%d\n", sent, len, dst_is_ipv4); HIP_DEBUG("Packet sent ok\n"); break; } } } out_err: /* Reset the interface to wildcard or otherwise receiving * broadcast messages fails from the raw sockets. A better * solution would be to have separate sockets for sending * and receiving because we cannot receive a broadcast while * sending */ if (dst_is_ipv4) { src4->sin_addr.s_addr = INADDR_ANY; src4->sin_family = AF_INET; sa_size = sizeof(struct sockaddr_in); } else { struct in6_addr any = IN6ADDR_ANY_INIT; src6->sin6_family = AF_INET6; ipv6_addr_copy(&src6->sin6_addr, &any); sa_size = sizeof(struct sockaddr_in6); } bind(hipfw_raw_sock_output, (struct sockaddr *) &src, sa_size); if (udp && memmoved) { /* Remove 32 bits of zero bytes between UDP and HIP */ len -= HIP_UDP_ZERO_BYTES_LEN + sizeof(struct udphdr); memmove((char *) msg, ((char *) msg) + HIP_UDP_ZERO_BYTES_LEN + sizeof(struct udphdr), len); memset(((char *) msg) + len, 0, HIP_UDP_ZERO_BYTES_LEN + sizeof(struct udphdr)); } if (err) { HIP_ERROR("strerror: %s\n", strerror(errno)); } return err; }