Пример #1
0
int udpclient(int argc, char *argv[])
{
    char *lhost, *lport, *phost, *pport, *rhost, *rport;
    list_t *clients = NULL;
    list_t *conn_clients;
    client_t *client;
    client_t *client2;
    socket_t *tcp_serv = NULL;
    socket_t *tcp_sock = NULL;
    socket_t *udp_sock = NULL;
    char data[MSG_MAX_LEN];
    char addrstr[ADDRSTRLEN];
    
    struct timeval curr_time;
    struct timeval check_time;
    struct timeval check_interval;
    struct timeval timeout;
    fd_set client_fds;
    fd_set read_fds;
    uint16_t tmp_id;
    uint8_t tmp_type;
    uint16_t tmp_len;
    uint16_t tmp_req_id;
    int num_fds;
    
    int ret;
    int i;
    
    signal(SIGINT, &signal_handler);

    i = 0;    
    lhost = (argc - i == 5) ? NULL : argv[i++];
    lport = argv[i++];
    phost = argv[i++];
    pport = argv[i++];
    rhost = argv[i++];
    rport = argv[i++];

    /* Check validity of ports (can't check ip's b/c might be host names) */
    ERROR_GOTO(!isnum(lport), "Invalid local port.", done);
    ERROR_GOTO(!isnum(pport), "Invalid proxy port.", done);
    ERROR_GOTO(!isnum(rport), "Invalid remote port.", done);
    
    srand(time(NULL));
    next_req_id = rand() % 0xffff;
    
    /* Create an empty list for the clients */
    clients = list_create(sizeof(client_t), p_client_cmp, p_client_copy,
                          p_client_free, 1);
    ERROR_GOTO(clients == NULL, "Error creating clients list.", done);

    /* Create and empty list for the connecting clients */
    conn_clients = list_create(sizeof(client_t), p_client_cmp, p_client_copy,
                               p_client_free, 1);
    ERROR_GOTO(conn_clients == NULL, "Error creating clients list.", done);

    /* Create a TCP server socket to listen for incoming connections */
    tcp_serv = sock_create(lhost, lport, ipver, SOCK_TYPE_TCP, 1, 1);
    ERROR_GOTO(tcp_serv == NULL, "Error creating TCP socket.", done);
    if(debug_level >= DEBUG_LEVEL1)
    {
        printf("Listening on TCP %s\n",
               sock_get_str(tcp_serv, addrstr, sizeof(addrstr)));
    }
    
    FD_ZERO(&client_fds);

    /* Initialize all the timers */
    timerclear(&timeout);
    check_interval.tv_sec = 0;
    check_interval.tv_usec = 500000;
    gettimeofday(&check_time, NULL);
    
    while(running)
    {
        if(!timerisset(&timeout))
            timeout.tv_usec = 50000;

        read_fds = client_fds;
        FD_SET(SOCK_FD(tcp_serv), &read_fds);

        ret = select(FD_SETSIZE, &read_fds, NULL, NULL, &timeout);
        PERROR_GOTO(ret < 0, "select", done);
        num_fds = ret;

        gettimeofday(&curr_time, NULL);

        /* Go through all the clients and check if didn't get an ACK for sent
           data during the timeout period */
        if(timercmp(&curr_time, &check_time, >))
        {
            for(i = 0; i < LIST_LEN(clients); i++)
            {
                client = list_get_at(clients, i);

                ret = client_check_and_resend(client, curr_time);
                if(ret == -2)
                {
                    disconnect_and_remove_client(CLIENT_ID(client), clients,
                                                 &client_fds, 1);
                    i--;
                    continue;
                }

                ret = client_check_and_send_keepalive(client, curr_time);
                if(ret == -2)
                {
                    disconnect_and_remove_client(CLIENT_ID(client), clients,
                                                 &client_fds, 1);
                    i--;
                }
            }

            timeradd(&curr_time, &check_interval, &check_time);
        }
        
        if(num_fds == 0)
            continue;

        /* Check if pending TCP connection to accept and create a new client
           and UDP connection if one is ready */
        if(FD_ISSET(SOCK_FD(tcp_serv), &read_fds))
        {
            tcp_sock = sock_accept(tcp_serv);
            if(tcp_sock == NULL)
                continue;
            udp_sock = sock_create(phost, pport, ipver, SOCK_TYPE_UDP, 0, 1);
            if(udp_sock == NULL)
            {
                sock_close(tcp_sock);
                sock_free(tcp_sock);
                continue;
            }

            client = client_create(next_req_id++, tcp_sock, udp_sock, 1);
            if(!client || !tcp_sock || !udp_sock)
            {
                if(tcp_sock)
                    sock_close(tcp_sock);
                if(udp_sock)
                    sock_close(udp_sock);
            }
            else
            {
                client2 = list_add(conn_clients, client, 1);
                client_free(client);
                client = NULL;
                
                client_send_hello(client2, rhost, rport, CLIENT_ID(client2));
                client_add_tcp_fd_to_set(client2, &client_fds);
                client_add_udp_fd_to_set(client2, &client_fds);
            }
            
            sock_free(tcp_sock);
            sock_free(udp_sock);
            tcp_sock = NULL;
            udp_sock = NULL;

            num_fds--;
        }

        /* Check for pending handshakes from UDP connection */
        for(i = 0; i < LIST_LEN(conn_clients) && num_fds > 0; i++)
        {
            client = list_get_at(conn_clients, i);
            
            if(client_udp_fd_isset(client, &read_fds))
            {
                num_fds--;
                tmp_req_id = CLIENT_ID(client);

                ret = client_recv_udp_msg(client, data, sizeof(data),
                                          &tmp_id, &tmp_type, &tmp_len);
                if(ret == 0)
                    ret = handle_message(client, tmp_id, tmp_type,
                                         data, tmp_len);

                if(ret < 0)
                {
                    disconnect_and_remove_client(tmp_req_id, conn_clients,
                                                 &client_fds, 1);
                    i--;
                }
                else
                {
                    client = list_add(clients, client, 1);
                    list_delete_at(conn_clients, i);
                    client_remove_udp_fd_from_set(client, &read_fds);
                    i--;
                }
            }
        }

        /* Check if data is ready from any of the clients */
        for(i = 0; i < LIST_LEN(clients); i++)
        {
            client = list_get_at(clients, i);

            /* Check for UDP data */
            if(num_fds > 0 && client_udp_fd_isset(client, &read_fds))
            {
                num_fds--;

                ret = client_recv_udp_msg(client, data, sizeof(data),
                                          &tmp_id, &tmp_type, &tmp_len);
                if(ret == 0)
                    ret = handle_message(client, tmp_id, tmp_type,
                                         data, tmp_len);
                if(ret < 0)
                {
                    disconnect_and_remove_client(CLIENT_ID(client), clients,
                                                 &client_fds, 1);
                    i--;
                    continue; /* Don't go to check the TCP connection */
                }
            }

            /* Check for TCP data */
            if(num_fds > 0 && client_tcp_fd_isset(client, &read_fds))
            {
                ret = client_recv_tcp_data(client);
                if(ret == -1)
                {
                    disconnect_and_remove_client(CLIENT_ID(client), clients,
                                                 &client_fds, 1);
                    i--;
                    continue;
                }
                else if(ret == -2)
                {
                    client_mark_to_disconnect(client);
                    disconnect_and_remove_client(CLIENT_ID(client),
                                                 clients, &client_fds, 0);
                }

                num_fds--;
            }

            /* send any TCP data that was ready */
            ret = client_send_udp_data(client);
            if(ret < 0)
            {
                disconnect_and_remove_client(CLIENT_ID(client), clients,
                                             &client_fds, 1);
                i--;
            }
        }

        /* Finally, send any udp data that's still in the queue */
        for(i = 0; i < LIST_LEN(clients); i++)
        {
            client = list_get_at(clients, i);
            ret = client_send_udp_data(client);

            if(ret < 0 || client_ready_to_disconnect(client))
            {
                disconnect_and_remove_client(CLIENT_ID(client), clients,
                                             &client_fds, 1);
                i--;
            }
        }
    }
    
  done:
    if(debug_level >= DEBUG_LEVEL1)
        printf("Cleaning up...\n");
    if(tcp_serv)
    {
        sock_close(tcp_serv);
        sock_free(tcp_serv);
    }
    if(udp_sock)
    {
        sock_close(udp_sock);
        sock_free(udp_sock);
    }
    if(clients)
        list_free(clients);
    if(conn_clients)
        list_free(conn_clients);
    if(debug_level >= DEBUG_LEVEL1)
        printf("Goodbye.\n");
    return 0;
}
Пример #2
0
int udpclient(int argc, char *argv[])
{

	list_t *clients = NULL;
	list_t *conn_clients;
	client_t *client;
	client_t *tunnel;
	client_t *client2;

	char data[MSG_MAX_LEN];
	char addrstr[ADDRSTRLEN];
	char taddrstr[ADDRSTRLEN];

	socket_t *tcp_sock = NULL;
	socket_t *udp_sock = NULL;
	socket_t *next_sock = NULL;

	struct timeval curr_time;
	struct timeval check_time;
	struct timeval check_interval;
	struct timeval timeout;
	fd_set client_fds;
	fd_set read_fds;
	uint16_t tmp_id;
	uint8_t tmp_type;
	uint16_t tmp_len;
	// uint16_t tmp_req_id;
	int num_fds;
	uint32_t sourceid;



	int ret;
	int i;

	signal(SIGINT, &signal_handler);

	i = 0;    
	lhost = (argc - i == 5) ? NULL : argv[i++];
	lport = argv[i++];
	rport = argv[i++];
	phost = argv[i++];
	pport = argv[i++];
	relays = atoi(argv[i++]);
	if(debug_level >= DEBUG_LEVEL1)
		printf("relays need %d \n",relays);


	/* Check validity of ports (can't check ip's b/c might be host names) */

	ERROR_GOTO(!isnum(lport), "Invalid listen port.", done);

	ERROR_GOTO(!isnum(rport), "Invalid recv port.", done);

	ERROR_GOTO(!isnum(pport), "Invalid inter port.", done);
	//ERROR_GOTO(!isnum(rport), "Invalid remote port.", done);

	srand(inet_addr(lhost));
	localid=(rand());
	generate_rsakey(lhost);
	if(debug_level >= DEBUG_LEVEL1)
	{
		printf("local id %d \n",localid);
	}
	next_req_id = rand() % 0xffff;

	/* Create an empty list for the clients */
	clients = list_create(sizeof(client_t), p_client_cmp, p_client_copy,
	                      p_client_free, 1);
	ERROR_GOTO(clients == NULL, "Error creating clients list.", done);

	/* Create and empty list for the connecting clients */
	conn_clients = list_create(sizeof(client_t), p_client_cmp, p_client_copy,
	                           p_client_free, 1);
	ERROR_GOTO(conn_clients == NULL, "Error creating conn_clients list.", done);

	relay_clients = list_create(sizeof(client_t), p_client_cmp, p_client_copy,
	                            p_client_free, 1);
	ERROR_GOTO(relay_clients == NULL, "Error creating clients list.", done);

	/* Create a TCP server socket to listen for incoming connections */
	tcp_serv = sock_create(lhost, lport, ipver, SOCK_TYPE_TCP, 1, 1);

	ERROR_GOTO(tcp_serv == NULL, "Error creating TCP socket.", done);
	udp_serv = sock_create(lhost, rport,ipver, SOCK_TYPE_UDP, 1, 1);
	ERROR_GOTO(udp_serv == NULL, "Error creating TCP socket.", done);
	if(debug_level >= DEBUG_LEVEL1)
	{
		printf("Listening on TCP %s,UDP %s \n",
		       sock_get_str(tcp_serv, addrstr, sizeof(addrstr)),sock_get_str(udp_serv, taddrstr, sizeof(taddrstr)));
	}
	next_sock = sock_create(phost, pport, ipver, SOCK_TYPE_UDP, 0, 1);

	msg_send_req(next_sock,lhost,rport,0,localid);	   
	sock_free(next_sock);		
	next_sock = NULL;		

	FD_ZERO(&client_fds);

	/* Initialize all the timers */
	timerclear(&timeout);
	check_interval.tv_sec = 0;
	check_interval.tv_usec = 500000;
	gettimeofday(&check_time, NULL);


	while(running)
	{
		if(!timerisset(&timeout))
			timeout.tv_usec = 50000;

		read_fds = client_fds;
		FD_SET(SOCK_FD(tcp_serv), &read_fds);
		FD_SET(SOCK_FD(udp_serv), &read_fds);

		ret = select(FD_SETSIZE, &read_fds, NULL, NULL, &timeout);
		PERROR_GOTO(ret < 0, "select", done);
		num_fds = ret;

		gettimeofday(&curr_time, NULL);

		/* Go through all the clients and check if didn't get an ACK for sent
		 data during the timeout period */
		if(timercmp(&curr_time, &check_time, >))
		{
			for(i = 0; i < LIST_LEN(clients); i++)
			{
				client = list_get_at(clients, i);

				ret = client_check_and_resend(client, curr_time);
				if(ret == -2)
				{
					disconnect_and_remove_client(CLIENT_ID(client), clients,
					                             &client_fds, 1);
					i--;
					continue;
				}

				ret = client_check_and_send_keepalive(client, curr_time);
				if(ret == -2)
				{
					disconnect_and_remove_client(CLIENT_ID(client), clients,
					                             &client_fds, 1);
					i--;
				}
			}

			timeradd(&curr_time, &check_interval, &check_time);
		}

		if(num_fds == 0)
			continue;

		/* Check if pending TCP connection to accept and create a new client
		 and UDP connection if one is ready */
		if(FD_ISSET(SOCK_FD(tcp_serv), &read_fds))
		{
			tcp_sock = sock_accept(tcp_serv);
			if(tcp_sock == NULL)
				continue;
			if(SelectMethod(tcp_sock->fd)==-1)
			{ 
				if(debug_level >= DEBUG_LEVEL1)
					printf("socks version error\n");
				return-1;
			}
			rhost=ParseCommand(tcp_sock->fd);
			if (0<LIST_LEN(relay_clients))
			{

				tunnel = list_get_at(relay_clients, 0);

				udp_sock =sock_copy(CLIENT_TCP_SOCK(tunnel));

				SOCK_FD(udp_sock)=socket(AF_INET, SOCK_DGRAM, 0); 					
			}

			if(udp_sock == NULL)
			{
				sock_close(tcp_sock);
				sock_free(tcp_sock);
				continue;
			}

			client = client_create(next_req_id++, localid, tcp_sock, udp_sock, 1);
			memcpy(client->rsakey,tunnel->rsakey,strlen(tunnel->rsakey));

			printf("expid rsakey is %s",client->rsakey);
			if(debug_level >= DEBUG_LEVEL1)
				printf("create client id %d \n",CLIENT_ID(client));
			if(!client || !tcp_sock || !udp_sock)
			{
				if(tcp_sock)
					sock_close(tcp_sock);
				if(udp_sock)
					sock_close(udp_sock);
			}
			else
			{
				client2 = list_add(conn_clients, client, 1);
				client_free(client);
				client = NULL;
				if(debug_level >= DEBUG_LEVEL1)
				{
					sock_get_str(CLIENT_TCP_SOCK(client2), addrstr,
					             sizeof(addrstr));				
					printf("tunnel(%d): local %s ",client2->sourceid, addrstr);
					sock_get_str(CLIENT_UDP_SOCK(client2), addrstr,
					             sizeof(addrstr));
					printf("to %s \n",addrstr);
				}
				client_send_hello(client2,rhost,CLIENT_ID(client2));
				client_add_tcp_fd_to_set(client2, &client_fds);
				//client_add_udp_fd_to_set(client2, &client_fds);
			}

			sock_free(tcp_sock);
			sock_free(udp_sock);
			tcp_sock = NULL;
			udp_sock = NULL;

			num_fds--;
		}

		/* Check for UDP data */
		if(FD_ISSET(SOCK_FD(udp_serv), &read_fds))
		{


			//ret = client_recv_udp_msg(client, data, sizeof(data),
			//                          &tmp_id, &tmp_type, &tmp_len,&sourceid);
			ret = msg_recv_msg(udp_serv, data, sizeof(data),
			                   &tmp_id, &tmp_type, &tmp_len,&sourceid);

			if(debug_level >= DEBUG_LEVEL2)
				printf("recv msg from %d type %d %d bytes \n ",sourceid,tmp_type,tmp_len);
			if(ret == 0)
				ret = handle_message(tmp_id, tmp_type,
				                     data, tmp_len,sourceid,clients, conn_clients);
			/*if(ret < 0)
			{

				disconnect_and_remove_client(tmp_id, clients,
				                             &client_fds, 1);

		}	*/		
		}

		/* Check if data is ready from any of the clients */
		for(i = 0; i < LIST_LEN(clients); i++)
		{
			client = list_get_at(clients, i);



			/* Check for TCP data */
			if(num_fds > 0 && client_tcp_fd_isset(client, &read_fds))
			{
				ret = client_recv_tcp_data(client);
				if(ret == -1)
				{
					disconnect_and_remove_client(CLIENT_ID(client), clients,
					                             &client_fds, 1);
					i--;
					continue;
				}
				else if(ret == -2)
				{
					client_mark_to_disconnect(client);
					disconnect_and_remove_client(CLIENT_ID(client),
					                             clients, &client_fds, 0);
				}

				num_fds--;
			}

			/* send any TCP data that was ready */
			ret = client_send_udp_data(client);
			if(ret < 0)
			{
				disconnect_and_remove_client(CLIENT_ID(client), clients,
				                             &client_fds, 1);
				i--;
			}
		}

		/* Finally, send any udp data that's still in the queue */
		for(i = 0; i < LIST_LEN(clients); i++)
		{
			client = list_get_at(clients, i);
			ret = client_send_udp_data(client);

			if(ret < 0 || client_ready_to_disconnect(client))
			{
				disconnect_and_remove_client(CLIENT_ID(client), clients,
				                             &client_fds, 1);
				i--;
			}
		}
	}

	done:
		if(debug_level >= DEBUG_LEVEL1)
			printf("Cleaning up...\n");
		if(tcp_serv)
	{
		sock_close(tcp_serv);
		sock_free(tcp_serv);
	}
		if(udp_serv)
	{
		sock_close(udp_serv);
		sock_free(udp_serv);
	}
		if(clients)
			list_free(clients);
		if(conn_clients)
			list_free(conn_clients);
		if(debug_level >= DEBUG_LEVEL1)
			printf("Goodbye.\n");
		return 0;
}
Пример #3
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;
}
Пример #4
0
int udpclient(int argc, char* argv[])
{
	char* lhost, *lport, *phost, *pport, *rhost, *rport;
	list_t* clients;
	list_t* conn_clients;
	client_t* client;
	client_t* client2;
	socket_t* tcp_serv = NULL;
	socket_t* tcp_sock = NULL;
	socket_t* udp_sock = NULL;
	char data[MSG_MAX_LEN];
	char addrstr[ADDRSTRLEN];
	char pport_s[6];
	struct timeval curr_time;
	struct timeval check_time;
	struct timeval check_interval;
	struct timeval timeout;
	fd_set client_fds;
	fd_set read_fds;
	uint16_t tmp_id;
	uint8_t tmp_type;
	uint16_t tmp_len;
	uint16_t tmp_req_id;
	int num_fds;
	int ret;
	int i;
	int icmp_sock ;
	int timeexc = -1;
	struct sockaddr_in src, dest, rsrc;
	struct hostent* hp;
	uint32_t timeexc_ip;
	signal(SIGINT, &signal_handler);
	i = 0;
	if(index(argv[i], 58) || index(argv[i], 46))
		lhost = argv[i++];
	else
		lhost = NULL;
	lport = argv[i++];
	phost = argv[i++];
	if(index(argv[i], 58) || index(argv[i], 46)) {
		snprintf(pport_s, 5, "2222");
		pport = pport_s;
	} else
		pport = argv[i++];
	rhost = argv[i++];
	rport = argv[i++];
	/* Get info about localhost IP */
	if(!lhost){
		char szHostName[255];
		gethostname(szHostName, 255);
		hp = gethostbyname(szHostName);
	}else{
		hp = gethostbyname(lhost);
	}
	memset(&rsrc, 0, sizeof(struct sockaddr_in));
	timeexc_ip				= *(uint32_t*)hp->h_addr_list[0];
	rsrc.sin_family			= AF_INET;
	rsrc.sin_port			= 0;
	rsrc.sin_addr.s_addr	= timeexc_ip;
	/* IP of destination */
	memset(&src, 0, sizeof(struct sockaddr_in));
	hp					  = gethostbyname(phost);
	timeexc_ip            = *(uint32_t*)hp->h_addr_list[0];
	src.sin_family        = AF_INET;
	src.sin_port          = 0;
	src.sin_addr.s_addr   = timeexc_ip;
	/* IP of where the fake packet (echo request) was going */
	hp = gethostbyname("3.3.3.3");
	memcpy(&dest.sin_addr, hp->h_addr, hp->h_length);
	inet_pton(AF_INET, "3.3.3.3", &(dest.sin_addr));
	srand(time(NULL));
	next_req_id = rand() % 0xffff;
	/* Create an empty list for the clients */
	clients = list_create(sizeof(client_t), p_client_cmp, p_client_copy,
						  p_client_free);
	ERROR_GOTO(clients == NULL, "Error creating clients list.", done);
	/* Create and empty list for the connecting clients */
	conn_clients = list_create(sizeof(client_t), p_client_cmp, p_client_copy,
							   p_client_free);
	ERROR_GOTO(conn_clients == NULL, "Error creating clients list.", done);
	/* Create a TCP server socket to listen for incoming connections */
	tcp_serv = sock_create(lhost, lport, ipver, SOCK_TYPE_TCP, 1, 1);
	ERROR_GOTO(tcp_serv == NULL, "Error creating TCP socket.", done);
	if(debug_level >= DEBUG_LEVEL1) {
		printf("Listening on TCP %s\n",
			   sock_get_str(tcp_serv, addrstr, sizeof(addrstr)));
	}
	FD_ZERO(&client_fds);
	/* Initialize all the timers */
	timerclear(&timeout);
	check_interval.tv_sec = 0;
	check_interval.tv_usec = 500000;
	gettimeofday(&check_time, NULL);
	/* open raw socket */
	create_icmp_socket(&icmp_sock);
	if(icmp_sock == -1) {
		printf("[main] can't open raw socket\n");
		exit(1);
	}
	while(running) {
		if(!timerisset(&timeout))
			timeout.tv_usec = 50000;
		if(++timeexc==100) {
			timeexc=0;
			/* Send ICMP TTL exceeded to penetrate remote NAT */
			send_icmp(icmp_sock, &rsrc, &src, &dest, 0);
		}
		read_fds = client_fds;
		FD_SET(SOCK_FD(tcp_serv), &read_fds);
		ret = select(FD_SETSIZE, &read_fds, NULL, NULL, &timeout);
		PERROR_GOTO(ret < 0, "select", done);
		num_fds = ret;
		gettimeofday(&curr_time, NULL);
		/* Go through all the clients and check if didn't get an ACK for sent
		   data during the timeout period */
		if(timercmp(&curr_time, &check_time, >)) {
			for(i = 0; i < LIST_LEN(clients); i++) {
				client = list_get_at(clients, i);
				ret = client_check_and_resend(client, curr_time);
				if(ret == -2) {
					disconnect_and_remove_client(CLIENT_ID(client), clients,
												 &client_fds);
					i--;
					continue;
				}
				ret = client_check_and_send_keepalive(client, curr_time);
				if(ret == -2) {
					disconnect_and_remove_client(CLIENT_ID(client), clients,
												 &client_fds);
					i--;
				}
			}
			timeradd(&curr_time, &check_interval, &check_time);
		}
		if(num_fds == 0) continue;
		timeexc=0;
		/* Check if pending TCP connection to accept and create a new client
		   and UDP connection if one is ready */
		if(FD_ISSET(SOCK_FD(tcp_serv), &read_fds)) {
			tcp_sock = sock_accept(tcp_serv);
			udp_sock = sock_create(phost, pport, ipver,
								   SOCK_TYPE_UDP, 0, 1);
			client = client_create(next_req_id++, tcp_sock, udp_sock, 1);
			if(!client || !tcp_sock || !udp_sock) {
				if(tcp_sock)
					sock_close(tcp_sock);
				if(udp_sock)
					sock_close(udp_sock);
			} else {
				client2 = list_add(conn_clients, client);
				client_free(client);
				client = NULL;
				client_send_hello(client2, rhost, rport, CLIENT_ID(client2));
				client_add_tcp_fd_to_set(client2, &client_fds);
				client_add_udp_fd_to_set(client2, &client_fds);
			}
			sock_free(tcp_sock);
			sock_free(udp_sock);
			tcp_sock = NULL;
			udp_sock = NULL;
			num_fds--;
		}
		/* Check for pending handshakes from UDP connection */
		for(i = 0; i < LIST_LEN(conn_clients) && num_fds > 0; i++) {
			client = list_get_at(conn_clients, i);
			if(client_udp_fd_isset(client, &read_fds)) {
				num_fds--;
				tmp_req_id = CLIENT_ID(client);
				ret = client_recv_udp_msg(client, data, sizeof(data),
										  &tmp_id, &tmp_type, &tmp_len);
				if(ret == 0)
					ret = handle_message(client, tmp_id, tmp_type,
										 data, tmp_len);
				if(ret < 0) {
					disconnect_and_remove_client(tmp_req_id, conn_clients,
												 &client_fds);
					i--;
				} else {
					client = list_add(clients, client);
					list_delete_at(conn_clients, i);
					client_remove_udp_fd_from_set(client, &read_fds);
					i--;
				}
			}
		}
		/* Check if data is ready from any of the clients */
		for(i = 0; i < LIST_LEN(clients) && num_fds > 0; i++) {
			client = list_get_at(clients, i);
			/* Check for UDP data */
			if(client_udp_fd_isset(client, &read_fds)) {
				num_fds--;
				ret = client_recv_udp_msg(client, data, sizeof(data),
										  &tmp_id, &tmp_type, &tmp_len);
				if(ret == 0)
					ret = handle_message(client, tmp_id, tmp_type,
										 data, tmp_len);
				if(ret < 0) {
					disconnect_and_remove_client(CLIENT_ID(client), clients,
												 &client_fds);
					i--;
					continue; /* Don't go to check the TCP connection */
				}
			}
			/* Check for TCP data */
			if(client_tcp_fd_isset(client, &read_fds)) {
				num_fds--;
				ret = client_recv_tcp_data(client);
				if(ret == 0)
					ret = client_send_udp_data(client);
#if 0 /* if udptunnel is taking up 100% of cpu, try including this */
				else if(ret == 1)
#ifdef _WIN32
					_sleep(1);
#else
					usleep(1000); /* Quick hack so doesn't use 100% of CPU if
                                     data wasn't ready yet (waiting for ack) */
#endif /*WIN32*/
#endif /*0*/
				if(ret < 0) {
					disconnect_and_remove_client(CLIENT_ID(client), clients,
												 &client_fds);
					i--;
				}
			}
		}
	}
done:
	if(debug_level >= DEBUG_LEVEL1)
		printf("Cleaning up...\n");
	if(tcp_serv) {
		sock_close(tcp_serv);
		sock_free(tcp_serv);
	}
	if(udp_sock) {
		sock_close(udp_sock);
		sock_free(udp_sock);
	}
	if(clients)
		list_free(clients);
	if(debug_level >= DEBUG_LEVEL1)
		printf("Goodbye.\n");
	return 0;
}