[hipl-dev] Re: [Merge] lp:~hipl-core/hipl/libhip into lp:hipl

  • From: Christof Mroz <christof.mroz@xxxxxxxxxxxxxx>
  • To: hipl-dev@xxxxxxxxxxxxx
  • Date: Tue, 14 Feb 2012 21:54:22 +0100

On 14.02.2012 21:34, Christof Mroz wrote:
+/**
>  + * Receive data from the peer associated with a socket.
>  + * Waits for base exchange if no host association exists.
>  + *
>  + * @note Data is currently sent unencrypted.
>  + *
>  + * @param fd        file descriptor of the socket to receive from
>  + * @param buf       buffer for received data
>  + * @param len       size of buf
>  + * @param flags     recvfrom() flags
>  + * @param addr      buffer for the associated peer HIT
>  + * @param addr_len  size of dst_hit
>  + * @return          number of bytes received on success, -1 otherwise
>  + */
>  +int hip_recvfrom(int fd, void *buf, size_t len, int flags,
>  +                 struct sockaddr *addr, socklen_t *addr_len)
>  +{
>  +    int                       err       = 0;
>  +    socklen_t                 socklen   = *addr_len;
>  +    struct sockaddr_in6      *peer_hit  = (struct sockaddr_in6 *) addr;
>  +    struct in6_addr           peer_addr = { { { 0 } } };
>  +    struct in6_addr          *peer_addr6;
>  +    struct in_addr           *peer_addr4;
>  +    struct hip_fd_info       *fd_info = NULL;
>  +    struct hip_packet_context ctx     = { 0 };
>  +    int                       (*read_control_msg)(int, struct 
hip_packet_context *, int) = NULL;
>  +
>  +
>  +    if ((fd_info = hip_socket_get_info(fd)) == NULL) {
>  +        HIP_ERROR("Fd %d is not a hip socket, exiting.\n", fd);
>  +        return -1;
>  +    }
>  +
>  +    /* Bind to a ephemeral port if the src port hasn't been bound yet */
>  +    if (fd_info->bound_port == 0) {
>  +        if (auto_bind(fd_info)) {
>  +            HIP_ERROR("Fail to bind the hip socket.\n");
>  +            return -1;
>  +        }
>  +    }
>  +
>  +    /* Handle BEX if HA hasn't establised */
>  +    if (!fd_info->ha) {
>  +        if (hip_await_bex(fd_info, addr)) {
>  +            HIP_ERROR("Base exchange not successful.\n");
>  +            return -1;
>  +        }
>  +    }
>  +
>  +    ctx.input_msg    = hip_msg_alloc();
>  +    ctx.output_msg   = hip_msg_alloc();
>  +    read_control_msg = fd_info->family == AF_INET ? hip_read_control_msg_v4
>  +                       : hip_read_control_msg_v6;
>  +
>  +    /* Loop until we get a non-control packet or a CLOSE packet */
>  +    while (fd_info->ha->state == HIP_STATE_ESTABLISHED) {
>  +        err = recvfrom(fd, buf, len, flags | MSG_PEEK, addr,&socklen);
>  +        HIP_DEBUG("Peek packet len: %d\n", err);
>  +        HIP_DEBUG("peer sockaddr: AF = %d, socklen = %d\n", 
addr->sa_family, socklen);
>  +        if (err<  0) {
>  +            perror("recvfrom");
>  +        }
>  +
>  +        /* Drop the packet if it doesn't come from the address associated
>  +         * with the correct peer. */
>  +        if (fd_info->proto == IPPROTO_UDP) {
>  +            if (addr->sa_family == AF_INET) {
>  +                peer_addr4 =&((struct sockaddr_in *) addr)->sin_addr;
>  +                IPV4_TO_IPV6_MAP(peer_addr4,&peer_addr);
>  +                peer_addr6 =&peer_addr;
>  +            } else {
>  +                peer_addr6 =&((struct sockaddr_in6 *) addr)->sin6_addr;
>  +            }
>  +            if (ipv6_addr_cmp(&fd_info->ha->peer_addr, peer_addr6)) {
>  +                HIP_DEBUG("Packet not from associated address. 
Dropping.\n");
>  +                HIP_DEBUG_IN6ADDR("expected",&fd_info->ha->peer_addr);
>  +                HIP_DEBUG_IN6ADDR("got", peer_addr6);
>  +                err = recvfrom(fd, buf, 1, flags, addr,&socklen);
>  +                HIP_IFEL(err<  0, err, "recvfrom()\n");
>  +                continue;
>  +            }
>  +        }
>  +
>  +        /* Receive message */
>  +        if (hip_is_control_msg(buf, err, fd_info)) {
>  +            HIP_DEBUG("receive a hip control message.\n");
>  +            if (fd_info->proto == IPPROTO_TCP) {
>  +                if (!hip_read_control_msg_tcp(fd,&ctx)) {
>  +                    hip_receive_control_packet(&ctx);
>  +                }
>  +            } else if (!read_control_msg(fd,&ctx, HIP_UDP_ZERO_BYTES_LEN)) {
>  +                hip_receive_control_packet(&ctx);
>  +            } else {
>  +                HIP_ERROR("Error reading control packet\n");
>  +            }
>  +            err = 0;
>  +        } else {
>  +            HIP_DEBUG("receive a non hip control message.\n");
>  +            err = recvfrom(fd, buf, len, flags, addr,&socklen);
>  +            HIP_IFEL(err<  0, err, "recvfrom() error\n");
>  +            break;
>  +        }
>  +    }
Unrelated: Could this be a possible DOS, by crafting a packet that triggers one 
of the nested recvfrom()s but never sends anything after that, causing it to 
recv forever?
If this is the "main socket", it would probably not hang but we could slurp 
bytes from genuine clients this way.


Never mind: the outer recvfrom() has MSG_PEEK set of course.

Other related posts: