/**
 * 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;
}
Exemple #2
0
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;
}
/**
 * Print all IP addresses where an update packet should be sent to.
 *
 * @param ha    pointer to a host association
 */
static void hip_print_addresses_to_send_update_request(const struct hip_hadb_state *const ha)
{
    const struct update_state *const localstate = lmod_get_state_item(ha->hip_modular_state, "update");

    HIP_DEBUG("Addresses to send update:\n");
    for (unsigned i = 0; i < localstate->valid_locators; i++) {
        HIP_DEBUG_IN6ADDR("", &localstate->addresses_to_send_echo_request[i]);
    }
}
static int select_source_address(struct in6_addr *src, const struct in6_addr *dst)
{
    int             err        = 0;
    int             family     = AF_INET;
    struct idxmap  *idxmap[16] = { 0 };
    struct in6_addr lpback     = IN6ADDR_LOOPBACK_INIT;

    HIP_DEBUG_IN6ADDR("dst", dst);

    /* Required for loopback connections */
    if (!ipv6_addr_cmp(dst, &lpback)) {
        ipv6_addr_copy(src, dst);
        goto out_err;
    }

    HIP_IFEL(hip_iproute_get(&hipfw_nl_route, src, dst, NULL, NULL, family, idxmap), -1, "Finding ip route failed\n");

    HIP_DEBUG_IN6ADDR("src", src);

out_err:
    return err;
}
Exemple #5
0
/** 
 * resolve_dht_gateway_info - Resolves the gateway address
 * @param gateway_name	FQDN of the gateway
 * @param gateway	Addrinfo struct where the result will be stored
 * @param af		address family
 * 
 * @return Returns 0 on success otherwise -1
 */
int resolve_dht_gateway_info(char *gateway_name, 
			     struct addrinfo ** gateway,
			     in_port_t gateway_port,
			     int af) {
    struct addrinfo hints;
    struct sockaddr_in  *sa_v4 = NULL;
    struct sockaddr_in6 *sa_v6 = NULL;
    int error;
    char opendht_serving_gateway_port_str[7];

    if ((af != AF_INET) && (af != AF_INET6)) {
	error = -1;
	HIP_DEBUG("Wrong address family!\n");
	return error;
    }

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = af;
    hints.ai_socktype = SOCK_STREAM;
    /* For some reason this does not work anymore -samu */
    //hints.ai_flags = AI_NODHT;
    error = 0;
    
    sprintf(opendht_serving_gateway_port_str, "%d", gateway_port);
    error = getaddrinfo(gateway_name, opendht_serving_gateway_port_str, &hints, gateway);
    if (error != 0) {
        HIP_DEBUG("OpenDHT gateway resolving failed %s\n", gateway_name);
	HIP_DEBUG("%s\n",gai_strerror(error));
    } else {
	if (af == AF_INET) {
	    sa_v4 = (struct sockaddr_in *) (*gateway)->ai_addr;
	    HIP_DEBUG_INADDR("OpenDHT gateway IPv4", &(sa_v4->sin_addr));
	} else if (af == AF_INET6) {
	    sa_v6 = (struct sockaddr_in6 *) (*gateway)->ai_addr;
	    HIP_DEBUG_IN6ADDR("OpenDHT gateway IPv6", &(sa_v6->sin6_addr));
	}
    }

    return error;
}
Exemple #6
0
/**
 * Convert a string representation of an IPv6 or IPv4 address to a struct
 * in6_addr.
 * If the string contains an IPv4 address, it is converted to its
 * IPv6-compatible mapping.
 *
 * @param str points to the string to convert.
 * @param ip6 points to a buffer where the function stores the binary address
 *  if it could be converted.
 * @return The return value is 0 if the conversion succeeds. It is a
 *  negative value if str or ip6 are NULL or if str contains neither a
 *  parseable IPv6 or IPv4 address.
 */
int hip_convert_string_to_address(const char *const str,
                                  struct in6_addr *const ip6)
{
    if (str && ip6) {
        if (inet_pton(AF_INET6, str, ip6) == 1) {
            /* IPv6 address conversion was ok */
            return 0;
        } else {
            struct in_addr ip4;

            /* Might be an ipv4 address (ret == 0). Lets catch it here. */
            if (inet_pton(AF_INET, str, &ip4) == 1) {
                IPV4_TO_IPV6_MAP(&ip4, ip6);
                HIP_DEBUG("Mapped v4 to v6.\n");
                HIP_DEBUG_IN6ADDR("mapped v6", ip6);
                return 0;
            }
        }
    }

    return -1;
}
Exemple #7
0
Fichier : lsi.c Projet : surki/hipl
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;
}
Exemple #8
0
Fichier : lsi.c Projet : surki/hipl
/**
 * Executes the packet reinjection
 *

 * @param src_hit              ipv6 source address 
 * @param dst_hit              ipv6 destination address
 * @param m                    pointer to the packet
 * @param ipOrigTraffic        type of Traffic (IPv4 or IPv6)
 * @param incoming             packet direction
 * @return	               err during the reinjection
 */
int reinject_packet(struct in6_addr *src_hit, struct in6_addr *dst_hit,
		    ipq_packet_msg_t *m, int ipOrigTraffic, int incoming)
{
        int err = 0, ip_hdr_size, packet_length = 0, protocol, ttl;
	u8 *msg;  
	struct icmphdr *icmp = NULL;

	if (ipOrigTraffic == 4) {
		struct ip *iphdr = (struct ip*) m->payload;
		ip_hdr_size = (iphdr->ip_hl * 4);  
		protocol = iphdr->ip_p;
		ttl = iphdr->ip_ttl;
        	HIP_DEBUG_LSI("Ipv4 address src ", &(iphdr->ip_src));
	        HIP_DEBUG_LSI("Ipv4 address dst ", &(iphdr->ip_dst));
	} else {
	        struct ip6_hdr* ip6_hdr = (struct ip6_hdr*) m->payload;
		ip_hdr_size = sizeof(struct ip6_hdr); //Fixed size
		protocol = ip6_hdr->ip6_nxt;
		ttl = ip6_hdr->ip6_hlim;
		HIP_DEBUG_IN6ADDR("Orig packet src address: ", &(ip6_hdr->ip6_src));
		HIP_DEBUG_IN6ADDR("Orig packet dst address: ", &(ip6_hdr->ip6_dst));
		HIP_DEBUG_IN6ADDR("New packet src address:", src_hit);
		HIP_DEBUG_IN6ADDR("New packet dst address: ", dst_hit);
	}
	
	if (m->data_len <= (BUFSIZE - ip_hdr_size)) {
		packet_length = m->data_len - ip_hdr_size; 	
	  	HIP_DEBUG("packet size smaller than buffer size\n");
	} else { 
	  	packet_length = BUFSIZE - ip_hdr_size;
		HIP_DEBUG("HIP packet size greater than buffer size\n");
	}

	_HIP_DEBUG("Reinject packet packet length (%d)\n", packet_length);
	_HIP_DEBUG("      Protocol %d\n", protocol);
	_HIP_DEBUG("      ipOrigTraffic %d \n", ipOrigTraffic);

	/* Note: using calloc to zero memory region here because I think
	   firewall_send_incoming_pkt() calculates checksum
	   from too long region sometimes. See bug id 874 */
	msg = (u8 *)calloc((packet_length + sizeof(struct ip)), 1);
	memcpy(msg, (m->payload)+ip_hdr_size, packet_length);

	if (protocol == IPPROTO_ICMP && incoming) {
		  icmp = (struct icmphdr *)msg;
		  HIP_DEBUG("incoming ICMP type=%d code=%d\n",
			    icmp->type,icmp->code);
		  /* Manually built due to kernel messed up with the
		     ECHO_REPLY message. Kernel was building an answer
		     message with equals @src and @dst*/
		  if (icmp->type == ICMP_ECHO) {
		  	icmp->type = ICMP_ECHOREPLY;
		    	err = firewall_send_outgoing_pkt(dst_hit, src_hit,
							 msg, packet_length,
							 protocol);
		  } else {
		    	err = firewall_send_incoming_pkt(src_hit, dst_hit,
							 msg, packet_length,
							 protocol, ttl);
		  }
	} else {
		  if (incoming) {
			    HIP_DEBUG("Firewall send to the kernel an incoming packet\n");
			    err = firewall_send_incoming_pkt(src_hit,
							     dst_hit, msg,
							     packet_length,
							     protocol, ttl);
		  } else {
			    HIP_DEBUG("Firewall send to the kernel an outgoing packet\n");
			    err = firewall_send_outgoing_pkt(src_hit,
							     dst_hit, msg,
							     packet_length,
							     protocol);
		  }
	}

	if(msg)
	        HIP_FREE(msg);
	return err;	
}
Exemple #9
0
/**
 *  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);
    }
}
Exemple #10
0
/* Moved function doxy descriptor to the header file. Lauri 11.03.2008 */
int hip_read_control_msg_all(int socket, struct hip_common *hip_msg,
                             struct in6_addr *saddr,
                             struct in6_addr *daddr,
                             hip_portpair_t *msg_info,
                             int encap_hdr_size, int is_ipv4)
{
	struct sockaddr_storage addr_from, addr_to;
	struct sockaddr_in *addr_from4 = ((struct sockaddr_in *) &addr_from);
	struct sockaddr_in6 *addr_from6 =
		((struct sockaddr_in6 *) &addr_from);
        struct cmsghdr *cmsg;
        struct msghdr msg;
	union {
		struct in_pktinfo *pktinfo_in4;
		struct inet6_pktinfo *pktinfo_in6;
	} pktinfo;
        struct iovec iov;
        char cbuff[CMSG_SPACE(256)];
        int err = 0, len;
	int cmsg_level, cmsg_type;

	HIP_ASSERT(saddr);
	HIP_ASSERT(daddr);

	HIP_DEBUG("hip_read_control_msg_all() invoked.\n");

	HIP_IFEL(((len = hip_peek_recv_total_len(socket, encap_hdr_size, HIP_DEFAULT_MSG_TIMEOUT))<= 0),
		 -1, "Bad packet length (%d)\n", len);

	memset(msg_info, 0, sizeof(hip_portpair_t));
	memset(&msg, 0, sizeof(msg));
	memset(cbuff, 0, sizeof(cbuff));
	memset(&addr_to, 0, sizeof(addr_to));

        /* setup message header with control and receive buffers */
        msg.msg_name = &addr_from;
        msg.msg_namelen = sizeof(struct sockaddr_storage);
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;

        memset(cbuff, 0, sizeof(cbuff));
        msg.msg_control = cbuff;
        msg.msg_controllen = sizeof(cbuff);
        msg.msg_flags = 0;

        iov.iov_len = len;
        iov.iov_base = hip_msg;

	pktinfo.pktinfo_in4 = NULL;

	len = recvmsg(socket, &msg, 0);

	HIP_IFEL((len < 0), -1, "ICMP%s error: errno=%d, %s\n",
		 (is_ipv4 ? "v4" : "v6"), errno, strerror(errno));

	cmsg_level = (is_ipv4) ? IPPROTO_IP : IPPROTO_IPV6;
	cmsg_type = (is_ipv4) ? IP_PKTINFO : IPV6_2292PKTINFO;

	/* destination address comes from ancillary data passed
	 * with msg due to IPV6_PKTINFO socket option */
	for (cmsg=CMSG_FIRSTHDR(&msg); cmsg; cmsg=CMSG_NXTHDR(&msg,cmsg)){
		if ((cmsg->cmsg_level == cmsg_level) &&
		    (cmsg->cmsg_type == cmsg_type)) {
			/* The structure is a union, so this fills also the
			   pktinfo_in6 pointer */
			pktinfo.pktinfo_in4 =
				(struct in_pktinfo*)CMSG_DATA(cmsg);
			break;
		}
	}

	/* If this fails, change IPV6_2292PKTINFO to IPV6_PKTINFO in
	   hip_init_raw_sock_v6 */
	HIP_IFEL(!pktinfo.pktinfo_in4, -1,
		 "Could not determine dst addr, dropping\n");

	/* UDP port numbers */
	if (is_ipv4 && encap_hdr_size == HIP_UDP_ZERO_BYTES_LEN) {
		HIP_DEBUG("hip_read_control_msg_all() source port = %d\n",
			  ntohs(addr_from4->sin_port));
		msg_info->src_port = ntohs(addr_from4->sin_port);
		/* Destination port is known from the bound socket. */
		msg_info->dst_port = hip_get_local_nat_udp_port();
	}

	/* IPv4 addresses */
	if (is_ipv4) {
		struct sockaddr_in *addr_to4 = (struct sockaddr_in *) &addr_to;
		IPV4_TO_IPV6_MAP(&addr_from4->sin_addr, saddr);
		IPV4_TO_IPV6_MAP(&pktinfo.pktinfo_in4->ipi_addr,
				 daddr);
		addr_to4->sin_family = AF_INET;
		addr_to4->sin_addr = pktinfo.pktinfo_in4->ipi_addr;
		addr_to4->sin_port = msg_info->dst_port;
	} else /* IPv6 addresses */ {
		struct sockaddr_in6 *addr_to6 =
			(struct sockaddr_in6 *) &addr_to;
		memcpy(saddr, &addr_from6->sin6_addr,
		       sizeof(struct in6_addr));
		memcpy(daddr, &pktinfo.pktinfo_in6->ipi6_addr,
		       sizeof(struct in6_addr));
		addr_to6->sin6_family = AF_INET6;
		ipv6_addr_copy(&addr_to6->sin6_addr, daddr);
	}

//added by santtu
	if (hip_read_control_msg_plugin_handler(hip_msg,len, saddr,msg_info->src_port))
		goto out_err;
//endadd

	if (is_ipv4 && (encap_hdr_size == IPV4_HDR_SIZE)) {/* raw IPv4, !UDP */
		/* For some reason, the IPv4 header is always included.
		   Let's remove it here. */
		memmove(hip_msg, ((char *)hip_msg) + IPV4_HDR_SIZE,
			HIP_MAX_PACKET - IPV4_HDR_SIZE);
	} else if (is_ipv4 && encap_hdr_size == HIP_UDP_ZERO_BYTES_LEN) {
		/* remove 32-bits of zeroes between UDP and HIP headers */
		memmove(hip_msg, ((char *)hip_msg) + HIP_UDP_ZERO_BYTES_LEN,
			HIP_MAX_PACKET - HIP_UDP_ZERO_BYTES_LEN);
	}

	HIP_IFEL(hip_verify_network_header(hip_msg,
					   (struct sockaddr *) &addr_from,
					   (struct sockaddr *) &addr_to,
					   len - encap_hdr_size), -1,
		 "verifying network header failed\n");



	if (saddr)
		HIP_DEBUG_IN6ADDR("src", saddr);
	if (daddr)
		HIP_DEBUG_IN6ADDR("dst", daddr);

 out_err:
	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;
}
Exemple #12
0
int main_server_udp(int ipv4_sock, int ipv6_sock, in_port_t local_port) {
	/* Use recvmsg/sendmsg instead of recvfrom/sendto because
	   the latter combination may choose a different source
	   HIT for the server */
	int err = 0, on = 1, recvnum, sendnum, is_ipv4 = 0;
	int cmsg_level, cmsg_type, highest_descriptor = -1;
        fd_set read_fdset;
	union {
		struct sockaddr_in in4;
		struct sockaddr_in6 in6;
	} peer_addr, local_addr;
	uint8_t cmsgbuf[CMSG_SPACE(sizeof(struct inet6_pktinfo))];
	uint8_t mylovemostdata[IP_MAXPACKET];
	struct iovec iov;
        struct cmsghdr *cmsg = (struct cmsghdr *) cmsgbuf;
	union {
		struct in_pktinfo *in4;
		struct inet6_pktinfo *in6;
	} pktinfo;
	struct msghdr msg;

	FD_ZERO(&read_fdset);
	FD_SET(ipv4_sock, &read_fdset);
	FD_SET(ipv6_sock, &read_fdset);
	highest_descriptor = maxof(2, ipv4_sock, ipv6_sock);

	printf("=== Server listening INADDR_ANY/IN6ADDR_ANY ===\n");
	
	while(select((highest_descriptor + 1), &read_fdset,
		     NULL, NULL, NULL)) {

		/* XX FIXME: receiving two packets at the same time */

		if (FD_ISSET(ipv4_sock, &read_fdset)) {
			is_ipv4 = 1;
			//FD_CLR(ipv4_sock, &read_fdset);
		} else if (FD_ISSET(ipv6_sock, &read_fdset)) {
			is_ipv4 = 0;
			//FD_CLR(ipv6_sock, &read_fdset);
		} else {
			printf("Unhandled select event\n");
			goto reset;
		}

		msg.msg_name = &peer_addr.in6;
		msg.msg_namelen = sizeof(struct sockaddr_in6);
		msg.msg_iov = &iov;
		msg.msg_iovlen = 1;
		msg.msg_control = cmsgbuf;
		msg.msg_controllen = sizeof(cmsgbuf);
		msg.msg_flags = 0;
		
		iov.iov_base = mylovemostdata;
		iov.iov_len = sizeof(mylovemostdata);
		
		memset(mylovemostdata, 0, sizeof(mylovemostdata));
		memset(&peer_addr, 0, sizeof(peer_addr));
		memset(cmsgbuf, 0, sizeof(cmsgbuf));

		recvnum = recvmsg((is_ipv4 ? ipv4_sock : ipv6_sock), &msg, 0);
		if (recvnum < 0) {
			perror("recvmsg\n");
			goto reset;
		}
		printf("Received %d bytes\n", recvnum);

		//is_ipv4 = IN6_IS_ADDR_V4MAPPED(&peer_addr.in6.sin6_addr);
	
		cmsg_level = (is_ipv4) ? IPPROTO_IP : IPPROTO_IPV6;
		cmsg_type = (is_ipv4) ? IP_PKTINFO : IPV6_2292PKTINFO;
	
		/* Local address comes from ancillary data passed
		 * with msg due to IPV6_PKTINFO socket option */
		for (cmsg=CMSG_FIRSTHDR(&msg); cmsg;
		     cmsg=CMSG_NXTHDR(&msg,cmsg)){
			if ((cmsg->cmsg_level == cmsg_level) &&
			    (cmsg->cmsg_type == cmsg_type)) {
				/* The structure is a union, so this fills
				   also the pktinfo_in6 pointer */
				pktinfo.in4 =
					(struct in_pktinfo *)CMSG_DATA(cmsg);
				break;
			}
		}
	
		if (is_ipv4) {
			local_addr.in4.sin_family = AF_INET;
			local_addr.in4.sin_port = htons(local_port);
			//local_addr.in4.sin_port = peer_addr.in6.sin6_port;
			local_addr.in4.sin_addr.s_addr =
				pktinfo.in4->ipi_addr.s_addr;
			HIP_DEBUG_INADDR("local addr",
					 &local_addr.in4.sin_addr);
			HIP_DEBUG("local port %d\n",
				  ntohs(local_addr.in4.sin_port));
			HIP_DEBUG_INADDR("peer addr",
					 &peer_addr.in4.sin_addr);
			HIP_DEBUG("peer port %d\n",
				  ntohs(peer_addr.in4.sin_port));
			
		} else {
			local_addr.in6.sin6_family = AF_INET6;
			memcpy(&local_addr.in6.sin6_addr,
			       &pktinfo.in6->ipi6_addr,
			       sizeof(struct in6_addr));
			local_addr.in6.sin6_port = htons(local_port);
			HIP_DEBUG_IN6ADDR("local addr",
					  &local_addr.in6.sin6_addr);
			HIP_DEBUG("local port %d\n",
				  ntohs(local_addr.in6.sin6_port));
			HIP_DEBUG_IN6ADDR("peer addr",
					  &peer_addr.in6.sin6_addr);
			HIP_DEBUG("peer port %d\n",
				  ntohs(peer_addr.in6.sin6_port));
		}

		err = udp_send_msg((is_ipv4 ? ipv4_sock : ipv6_sock),
				   mylovemostdata, recvnum,
				   (struct sockaddr *) &local_addr,
				   (struct sockaddr *) &peer_addr);
		if (err) {
			printf("Failed to echo data back\n");
		}

	reset:

		FD_ZERO(&read_fdset);
		FD_SET(ipv4_sock, &read_fdset);
		FD_SET(ipv6_sock, &read_fdset);
	}

out_err:
	return err;
}
Exemple #13
0
/* Security associations in the kernel with BEET are bounded to the outer
 * address, meaning IP addresses. As a result the parameters to be given
 * should be such an addresses and not the HITs.
 */
uint32_t hip_add_sa(struct in6_addr *saddr, struct in6_addr *daddr,
		    struct in6_addr *src_hit, struct in6_addr *dst_hit,
		    uint32_t spi, int ealg, struct hip_crypto_key *enckey,
		    struct hip_crypto_key *authkey,
		    int already_acquired, int direction, int update,
		    hip_ha_t *entry)
{

	int so, len, err = 0, e_keylen, a_keylen;
	int aalg = ealg;
	u_int wsize = 4;  /* XXX static size of window */
	struct sockaddr_storage ss_addr, dd_addr;
	struct sockaddr *s_saddr;
	struct sockaddr *d_saddr;
	uint32_t reqid = 0;
	u_int32_t seq = 0;
	u_int flags = 0; // always zero
	u_int64_t lifebyte = 0, lifetime = 0;
	//u_int8_t l_natt_type = HIP_UDP_ENCAP_ESPINUDP_NON_IKE;
	u_int8_t l_natt_type = HIP_UDP_ENCAP_ESPINUDP;
	// FIXME: this parameter maybe should be related to some esp parameters (according to racoon source code)
	u_int16_t l_natt_frag = 0;
	/* Mappings from HIP to PFKEY algo names */
	u_int e_types[] = {SADB_EALG_NULL, SADB_X_EALG_AESCBC, SADB_EALG_3DESCBC, SADB_EALG_3DESCBC,
			   SADB_X_EALG_BLOWFISHCBC, SADB_EALG_NULL, SADB_EALG_NULL};
	u_int a_algos[] = {SADB_AALG_NONE, SADB_AALG_SHA1HMAC, SADB_AALG_SHA1HMAC, SADB_AALG_MD5HMAC,
			   SADB_AALG_SHA1HMAC, SADB_AALG_SHA1HMAC, SADB_AALG_MD5HMAC};
	u_int e_type = e_types[ealg];
	u_int a_type = a_algos[aalg];
	in_port_t sport = entry->local_udp_port;
	in_port_t dport = entry->peer_udp_port;

	a_keylen = hip_auth_key_length_esp(ealg);
	e_keylen = hip_enc_key_length(ealg);

	get_random_bytes(&reqid, sizeof(uint32_t));
	get_random_bytes(&seq, sizeof(uint32_t));

	HIP_DEBUG("\n");
	HIP_DEBUG_HIT("src_hit", src_hit);
	HIP_DEBUG_HIT("dst_hit", dst_hit);
	HIP_DEBUG_IN6ADDR("saddr", saddr);
	HIP_DEBUG_IN6ADDR("daddr", daddr);
	HIP_IFEL((!saddr || !daddr), 1, "Addresses not valid when adding SA's\n");

	HIP_IFEL(((so = pfkey_open()) < 0), 1, "ERROR in opening pfkey socket: %s\n", ipsec_strerror());

	s_saddr = (struct sockaddr*) &ss_addr;
	d_saddr = (struct sockaddr*) &dd_addr;
	get_sock_addr_from_in6(s_saddr, saddr);
	get_sock_addr_from_in6(d_saddr, daddr);

	if (direction == HIP_SPI_DIRECTION_OUT)
	{
		entry->outbound_sa_count++;
	}
	else
	{
		entry->inbound_sa_count++;
	}


	// NOTE: port numbers remains in host representation
	if (update) {
		if (sport) {
			// pfkey_send_update_nat when update = 1 and sport != 0
			HIP_IFEBL(((len = pfkey_send_update_nat(so, SADB_SATYPE_ESP, HIP_IPSEC_DEFAULT_MODE, 
								s_saddr, d_saddr, spi, reqid, wsize,
								(void*) enckey, e_type, e_keylen, 
								a_type, a_keylen, flags,
								0, lifebyte, lifetime, 0, seq,
								l_natt_type, sport, dport, NULL,
								l_natt_frag)) < 0),
				  1, pfkey_close(so), "ERROR in updating sa for nat: %s\n", ipsec_strerror());
		} else {
			// pfkey_send_update when update = 1 and sport == 0
			HIP_IFEBL(((len = pfkey_send_update(so, SADB_SATYPE_ESP, HIP_IPSEC_DEFAULT_MODE,
							    s_saddr, d_saddr, spi, reqid, wsize,
							    (void*) enckey, e_type, e_keylen,
							    a_type, a_keylen, flags,
							    0, lifebyte, lifetime, 0, seq)) < 0),
				  1, pfkey_close(so), "ERROR in updating sa: %s\n", ipsec_strerror());
		}
	} else {
		if (sport) {
			// pfkey_send_add_nat when update = 0 and sport != 0 	
			HIP_IFEBL(((len = pfkey_send_add_nat(so, SADB_SATYPE_ESP, HIP_IPSEC_DEFAULT_MODE,
							     s_saddr, d_saddr, spi, reqid, wsize,
							     (void*) enckey, e_type, e_keylen, 
							     a_type, a_keylen, flags,
							     0, lifebyte, lifetime, 0, seq,
							     l_natt_type, sport, dport, NULL,
							     l_natt_frag)) < 0),
				  1, pfkey_close(so), "ERROR in adding sa for nat: %s\n", ipsec_strerror());
		} else {
			// pfkey_send_add when update = 0 and sport == 0
			HIP_IFEBL(((len = pfkey_send_add(so, SADB_SATYPE_ESP, HIP_IPSEC_DEFAULT_MODE,
							 s_saddr, d_saddr, spi, reqid, wsize,
							 (void*) enckey, e_type, e_keylen,
							 a_type, a_keylen, flags,
							 0, lifebyte, lifetime, 0, seq)) < 0),
				  1, pfkey_close(so), "ERROR in adding sa: %s\n", ipsec_strerror());
		}
	}

	return 0;

out_err:
	return err;
}