/** * handle_locator_value - This function copies the 2nd address (ipv4) from * the locator from packet returned from lookup * * @param *packet response returned from the lookup service * @param *locator_ipv4 opaque pointer passed to point to the ipv4 address * @return status of the operation 0 on success, -1 on failure */ int handle_locator_value (unsigned char *packet, void *locator_ipv4) { struct hip_locator *locator; struct hip_locator_info_addr_item *locator_address_item = NULL; int locator_item_count = 0; struct in6_addr addr6; struct in_addr addr4; locator = hip_get_param((struct hip_common *)packet, HIP_PARAM_LOCATOR); if (locator) { locator_item_count = hip_get_locator_addr_item_count(locator); locator_item_count--; locator_address_item = hip_get_locator_first_addr_item(locator); memcpy(&addr6, (struct in6_addr*)&locator_address_item[locator_item_count].address, sizeof(struct in6_addr)); if (IN6_IS_ADDR_V4MAPPED(&addr6)) { IPV6_TO_IPV4_MAP(&addr6, &addr4); sprintf((char*)locator_ipv4, "%s", inet_ntoa(addr4)); } else { hip_in6_ntop(&addr6, (char*)locator_ipv4); _HIP_DEBUG("Value: %s\n", (char*)locator_ipv4); } return 0 ; } else return -1; }
/* * This function converts the netdev_address structure src into * a character string, which is copied to a character buffer dst, which is cnt bytes long. */ const char *netdev_address_to_str(struct netdev_address *src, char *dst, socklen_t cnt) { struct sockaddr *tmp_sockaddr_ptr = (struct sockaddr*) &(src->addr); struct sockaddr_in *tmp_sockaddr_in_ptr = (struct sockaddr_in*) tmp_sockaddr_ptr; struct sockaddr_in6 *tmp_sockaddr_in6_ptr = (struct sockaddr_in6*) tmp_sockaddr_ptr; struct in_addr tmp_in_addr; struct in6_addr *tmp_in6_addr_ptr = NULL; void *inet_ntop_src = NULL; int af = tmp_sockaddr_ptr->sa_family ; // might be changed because of ip4->ip6 mapping switch (af) { case AF_INET: inet_ntop_src = & (tmp_sockaddr_in_ptr->sin_addr); break; case AF_INET6: tmp_in6_addr_ptr = & (tmp_sockaddr_in6_ptr->sin6_addr); if (IN6_IS_ADDR_V4MAPPED(tmp_in6_addr_ptr)) { IPV6_TO_IPV4_MAP(tmp_in6_addr_ptr, &tmp_in_addr) af = AF_INET; inet_ntop_src = &tmp_in_addr; } else inet_ntop_src = tmp_in6_addr_ptr; break; } return inet_ntop(af, inet_ntop_src, dst, cnt); }
/** * print a HIT * * @param debug_level the urgency of the message (DEBUG_LEVEL_XX) * @param file the file from where the debug call was made * @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 str string to be printed before the HIT * @param hit the HIT to be printed * @note Do not call this function directly. Instead, use the * HIP_DEBUG_HIT and HIP_INFO_HIT macros. */ void hip_print_hit(int debug_level, const char *file, int line, const char *function, const char *str, const struct in6_addr *hit) { if (hit == NULL) { HIP_DEBUG("%s: NULL\n", str); return; } else { char dst[INET6_ADDRSTRLEN]; if (IN6_IS_ADDR_V4MAPPED(hit)) { struct in_addr in_addr; IPV6_TO_IPV4_MAP(hit, &in_addr); hip_print_lsi(debug_level, file, line, function, str, &in_addr); } else { hip_in6_ntop(hit, dst); hip_print_str(debug_level, file, line, function, "%s: %s\n", str, dst); } return; } }
/** * 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; }
int hip_fw_handle_incoming_hit(ipq_packet_msg_t *m, struct in6_addr *ip_src, struct in6_addr *ip_dst, int lsi_support, int sys_opp_support) { int bind6 = 0, proto4_LSI = 0, proto4_IP = 0, err = 0, verdict = 1; int ip_hdr_size = 0, portDest = 0, process_as_lsi; char *proto = NULL; hip_lsi_t lsi_our = {0}, lsi_peer = {0}; struct in6_addr src_addr, dst_addr; struct in_addr src_v4, dst_v4; struct ip6_hdr* ip6_hdr = (struct ip6_hdr*) m->payload; firewall_port_cache_hl_t *port_cache_entry = NULL; ip_hdr_size = sizeof(struct ip6_hdr); switch (ip6_hdr->ip6_nxt) { case IPPROTO_UDP: portDest = ((struct udphdr*)((m->payload) + ip_hdr_size))->dest; proto = "udp6"; break; case IPPROTO_TCP: portDest = ((struct tcphdr*)((m->payload) + ip_hdr_size))->dest; proto = "tcp6"; break; case IPPROTO_ICMPV6: HIP_DEBUG("ICMPv6 packet\n"); //goto out_err; break; default: HIP_DEBUG("Unhandled packet %d\n", ip6_hdr->ip6_nxt); //goto out_err; break; } /* port caching */ port_cache_entry = firewall_port_cache_db_match(portDest, ip6_hdr->ip6_nxt); if( port_cache_entry && (port_cache_entry->traffic_type == FIREWALL_PORT_CACHE_IPV6_TRAFFIC) ){ verdict = 1; HIP_DEBUG("Cached port, accepting\n"); goto out_err; } if (sys_opp_support && lsi_support) { /* Currently preferring LSIs over opp. connections */ process_as_lsi = 1; } else if (lsi_support) { process_as_lsi = 1; } else if (sys_opp_support) { process_as_lsi = 0; } else { HIP_ASSERT(1); } //HIP_IFEL(firewall_cache_db_match(ip_src, ip_dst, HIP_IFEL(firewall_cache_db_match(ip_dst, ip_src, &lsi_our, &lsi_peer, &dst_addr, &src_addr, NULL), -1, "Failed to obtain from cache\n"); if (process_as_lsi) { HIP_DEBUG("Trying lsi transformation\n"); HIP_DEBUG_LSI("lsi_our: ", &lsi_our); HIP_DEBUG_LSI("lsi_peer: ", &lsi_peer); IPV4_TO_IPV6_MAP(&lsi_our, &src_addr); IPV4_TO_IPV6_MAP(&lsi_peer, &dst_addr); HIP_IFEL(reinject_packet(&dst_addr, &src_addr, m, 6, 1), -1, "Failed to reinject with LSIs\n"); HIP_DEBUG("Successful LSI transformation.\n"); if (ip6_hdr->ip6_nxt == IPPROTO_ICMPV6) verdict = 1; /* broadcast: dst may be ipv4 or ipv6 */ else verdict = 0; /* drop original */ } else { HIP_DEBUG("Trying sys opp transformation\n"); IPV6_TO_IPV4_MAP(&src_addr, &src_v4); IPV6_TO_IPV4_MAP(&dst_addr, &dst_v4); HIP_DEBUG_IN6ADDR("ip_src: ", &src_addr); HIP_DEBUG_IN6ADDR("ip_dst: ", &dst_addr); HIP_IFEL(reinject_packet(&src_addr, &dst_addr, m, 6, 1), -1, "Failed to reinject with IP addrs\n"); HIP_DEBUG("Successfull sysopp transformation. Drop orig\n"); verdict = 0; } out_err: if (err) return 1; /* Accept original */ else return verdict; }
/** * 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"); } }
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; }