Пример #1
0
/*
 * Copy data to the internal buffer for sending to tcp connection and send ACK
 * back to tunnel. Returns 0 on success, 1 if this was "resending" data, -1
 * on error, or -2 if need to disconnect.
 */
int client_got_udp_data(client_t* client, char* data, int data_len,
						uint8_t msg_type)
{
	int ret;
	int is_resend = 0;
	if(data_len > MSG_MAX_LEN)
		return -1;
	/* Check if got new data, which is when got the data type (DATA0 or DATA1)
	   that it was waiting for, and write that new data to the buffer. */
	if((msg_type == MSG_TYPE_DATA0 &&
		client->udp2tcp_state == CLIENT_WAIT_DATA0)
	   || (msg_type == MSG_TYPE_DATA1 &&
		   client->udp2tcp_state == CLIENT_WAIT_DATA1)) {
		memcpy(client->udp2tcp, data, data_len);
		client->udp2tcp_len = data_len;
	} else
		is_resend = 1; /* Otherwise, the other host resent the data */
	msg_type = (msg_type == MSG_TYPE_DATA0) ? MSG_TYPE_ACK0 : MSG_TYPE_ACK1;
	/* Send the ACK for the data */
	ret = msg_send_msg(client->udp_sock, client->id, msg_type, NULL, 0);
	if(ret < 0)
		return ret;
	if(is_resend)
		return 1;
	/* Set the state to wait for the next type of data */
	client->udp2tcp_state = client->udp2tcp_state == CLIENT_WAIT_DATA0 ?
							CLIENT_WAIT_DATA1 : CLIENT_WAIT_DATA0;
	return 0;
}
Пример #2
0
/*
 * Sends the data in the tcp2udp buffer to the UDP tunnel. Returns 0 for
 * success, -1 on error, and -2 if needs to disconnect.
 */
int client_send_udp_data(client_t* client)
{
	uint8_t msg_type;
	int ret;
	if(client->resend_count >= CLIENT_MAX_RESEND)
		return -2;
	/* Set the message type it is sending. If the client is in the WAIT_ACK
	   state, then it will send the same type of data again (since this would
	   have been called b/c of a timeout. */
	switch(client->tcp2udp_state) {
	case CLIENT_WAIT_DATA0:
	case CLIENT_WAIT_ACK0:
		msg_type = MSG_TYPE_DATA0;
		break;
	case CLIENT_WAIT_DATA1:
	case CLIENT_WAIT_ACK1:
		msg_type = MSG_TYPE_DATA1;
		break;
	default:
		return -1;
	}
	ret = msg_send_msg(client->udp_sock, client->id, msg_type,
					   client->tcp2udp, client->tcp2udp_len);
	if(ret < 0)
		return ret;
	/* Set the state to wait for an ACK and set the timeout to some time in
	   the future */
	client->tcp2udp_state = (msg_type == MSG_TYPE_DATA0) ?
							CLIENT_WAIT_ACK0 : CLIENT_WAIT_ACK1;
	gettimeofday(&client->tcp2udp_timeout, NULL);
	client->tcp2udp_timeout.tv_sec += (client->resend_count+1)*CLIENT_TIMEOUT;
	return 0;
}
Пример #3
0
/*
 * Sends a goodbye message to the UDP server.
 */
int client_send_goodbye(client_t* client)
{
	return msg_send_msg(client->udp_sock, client->id, MSG_TYPE_GOODBYE,
						NULL, 0);
}
Пример #4
0
/*
 * Sends a Hello ACK to the UDP tunnel.
 */
int client_send_helloack(client_t* client, uint16_t req_id)
{
	req_id = htons(req_id);
	return msg_send_msg(client->udp_sock, client->id, MSG_TYPE_HELLOACK,
						(char*)&req_id, sizeof(req_id));
}
Пример #5
0
/*
 * Handles the message received from the UDP tunnel. Returns 0 for success, -1
 * for some error that it handled, and -2 if the connection should be
 * disconnected.
 */
int handle_message(uint16_t id, uint8_t msg_type, char *data, int data_len,
                   socket_t *from, list_t *clients, fd_set *client_fds,
                   list_t *allowed_destinations, char *port_str)
{
    client_t *c = NULL;
    client_t *c2 = NULL;
    socket_t *tcp_sock = NULL;
    int ret = 0;
    
    if(id != 0)
    {
        c = list_get(clients, &id);
        if(!c)
            return -1;
    }

    if(id == 0 && msg_type != MSG_TYPE_HELLO)
        return -2;
    
    switch(msg_type)
    {
        case MSG_TYPE_GOODBYE:
            ret = -2;
            break;
            
        /* Data in the hello message will be like "hostname port", possibly
           without the null terminator. This will look for the space and
           parse out the hostname or ip address and port number */
        case MSG_TYPE_HELLO:
        {
            int i;
            char port[6]; /* need this so port str can have null term. */
            char addrstr[ADDRSTRLEN];
            uint16_t req_id;
            
            if(id != 0)
                break;

            req_id = ntohs(*((uint16_t*)data));
            data += sizeof(uint16_t);
            data_len -= sizeof(uint16_t);
            
            /* look for the space separating the host and port */
            for(i = 0; i < data_len; i++)
                if(data[i] == ' ')
                    break;
            if(i == data_len)
                break;

            /* null terminate the host and get the port number to the string */
            data[i++] = 0;
            strncpy(port, data+i, data_len-i);
            port[data_len-i] = 0;

            if (!destination_allowed(allowed_destinations, data, port))
            {
                if (debug_level >= DEBUG_LEVEL1)
                    printf("Connection to %s:%s denied\n", data, port);
                msg_send_msg(from, next_client_id, MSG_TYPE_GOODBYE, NULL, 0);
                return -2;
            }
            
            /* Create an unconnected TCP socket for the remote host, the
               client itself, add it to the list of clients */
            tcp_sock = sock_create(data, port, ipver, SOCK_TYPE_TCP, 0, 0);
            ERROR_GOTO(tcp_sock == NULL, "Error creating tcp socket", error);

            c = client_create(next_client_id++, tcp_sock, from, 0);
            sock_free(tcp_sock);
            ERROR_GOTO(c == NULL, "Error creating client", error);

            c2 = list_add(clients, c);
            ERROR_GOTO(c2 == NULL, "Error adding client to list", error);

            if(debug_level >= DEBUG_LEVEL1)
            {
                sock_get_str(c2->udp_sock, addrstr, sizeof(addrstr));
                printf("New connection(%d): udp://%s", CLIENT_ID(c2), addrstr);
                sock_get_str(c2->tcp_sock, addrstr, sizeof(addrstr));
                printf(" -> tcp://%s\n", addrstr);
            }
            
            /* Send the Hello ACK message if created client successfully */
            client_send_helloack(c2, req_id);
            client_reset_keepalive(c2);
            client_free(c);
            
            break;
        }

        /* Can connect to TCP connection once received the Hello ACK */
        case MSG_TYPE_HELLOACK:
            client_got_helloack(c);
            client_connect_tcp(c, port_str);
            client_add_tcp_fd_to_set(c, client_fds);
            break;

        /* Resets the timeout of the client's keep alive time */
        case MSG_TYPE_KEEPALIVE:
            client_reset_keepalive(c);
            break;

        /* Receives the data it got from the UDP tunnel and sends it to the
           TCP connection. */
        case MSG_TYPE_DATA0:
        case MSG_TYPE_DATA1:
            ret = client_got_udp_data(c, data, data_len, msg_type);
            if(ret == 0)
                ret = client_send_tcp_data(c);
            break;

        /* Receives the ACK from the UDP tunnel to set the internal client
           state. */
        case MSG_TYPE_ACK0:
        case MSG_TYPE_ACK1:
            client_got_ack(c, msg_type);
            break;

        default:
            ret = -1;
    }

    return ret;

  error:
    return -1;
}