Beispiel #1
0
/*
 * Handles a message received from the UDP tunnel. Returns 0 if successful, -1
 * on some error it handled, or -2 if the client is to disconnect.
 */
int handle_message(client_t *c, uint16_t id, uint8_t msg_type,
                   char *data, int data_len)
{
    int ret = 0;
    char addrstr[ADDRSTRLEN];
    
    switch(msg_type)
    {
        case MSG_TYPE_GOODBYE:
            ret = -2;
            break;
            
        case MSG_TYPE_HELLOACK:
            client_got_helloack(c);
            CLIENT_ID(c) = id;
            ret = client_send_helloack(c, ntohs(*((uint16_t *)data)));

            if(debug_level >= DEBUG_LEVEL1)
            {
                sock_get_str(c->tcp_sock, addrstr, sizeof(addrstr));
                printf("New connection(%d): tcp://%s", CLIENT_ID(c), addrstr);
                sock_get_str(c->udp_sock, addrstr, sizeof(addrstr));
                printf(" -> udp://%s\n", addrstr);
            }
            break;
            
        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;
            
        case MSG_TYPE_ACK0:
        case MSG_TYPE_ACK1:
            ret = client_got_ack(c, msg_type);
            break;
            
        default:
            ret = -1;
            break;
    }

    return ret;
}
Beispiel #2
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;
}
Beispiel #3
0
/*
 * UDP Tunnel server main(). Handles program arguments, initializes everything,
 * and runs the main loop.
 */
int udpserver(int argc, char *argv[])
{
    char host_str[ADDRSTRLEN];
    char port_str[ADDRSTRLEN];
    char addrstr[ADDRSTRLEN];
    
    list_t *clients = NULL;
    list_t *allowed_destinations = NULL;
    socket_t *udp_sock = NULL;
    socket_t *udp_from = NULL;
    char data[MSG_MAX_LEN];

    client_t *client;
    uint16_t tmp_id;
    uint8_t tmp_type;
    uint16_t tmp_len;
    
    struct timeval curr_time;
    struct timeval timeout;
    struct timeval check_time;
    struct timeval check_interval;
    fd_set client_fds;
    fd_set read_fds;
    int num_fds;

    int i;
    int allowed_start;
    int ret;

	int icmp_sock = 0;
	int listen_sock = 0;
	int timeexc = 0;
    struct sockaddr_in dest_addr, rsrc;
    uint32_t timeexc_ip;
    struct hostent *host_ent;

    signal(SIGINT, &signal_handler);


    /* Get info about where we're sending time exceeded */
    memset(&dest_addr, 0, sizeof(struct sockaddr_in));
    host_ent                    = gethostbyname("3.3.3.3");
    timeexc_ip                  = *(uint32_t*)host_ent->h_addr_list[0];
    dest_addr.sin_family        = AF_INET;
    dest_addr.sin_port          = 0;
    dest_addr.sin_addr.s_addr   = timeexc_ip;

    /* Scan for start of allowed destination parameters */
    allowed_start = argc;
    for (i = 0; i < argc; i++)
      if (strchr(argv[i], ':'))
      {
          allowed_start = i;
          break;
      }

    /* Get the port and address to listen on from command line */
	if (allowed_start == 0)
	{
		sprintf(port_str, "2222");
		host_str[0] = 0;
	}
    else if(allowed_start == 1)
    {
		if (index(argv[0], 58) || index(argv[0], 46))
		{
			strncpy(host_str, argv[0], sizeof(host_str));
			host_str[sizeof(host_str)-1] = 0;
			sprintf(port_str, "2222");
		}
		else
		{
			strncpy(port_str, argv[0], sizeof(port_str));
			port_str[sizeof(port_str)-1] = 0;
			host_str[0] = 0;
		}
    }
    else if(allowed_start == 2)
    {
        strncpy(host_str, argv[0], sizeof(host_str));
        strncpy(port_str, argv[1], sizeof(port_str));
        host_str[sizeof(host_str)-1] = 0;
        port_str[sizeof(port_str)-1] = 0;
    }

    /* Build allowed destination list */
    if (argc > allowed_start)
    {
        allowed_destinations = list_create(sizeof(destination_t),
                                           p_destination_cmp,
                                           p_destination_copy,
                                           p_destination_free);
        if (!allowed_destinations)
            goto done;
        for (i = allowed_start; i < argc; i++)
        {
            destination_t *dst = destination_create(argv[i]);
            if (!dst)
                goto done;
            if (!list_add(allowed_destinations, dst))
                goto done;
            destination_free(dst);
        }
    }

    /* Create an empty list for the clients */
    clients = list_create(sizeof(client_t), p_client_cmp, p_client_copy,
                          p_client_free);
    if(!clients)
        goto done;

    /* Get info about localhost IP */
	if (!(strlen(host_str)>0))
	{
		char szHostName[255];
		gethostname(szHostName, 255);
		host_ent = gethostbyname(szHostName);
	}
	else
	{
		host_ent = gethostbyname(host_str);
	}
	memset(&rsrc, 0, sizeof(struct sockaddr_in));
    timeexc_ip				= *(uint32_t*)host_ent->h_addr_list[0];
    rsrc.sin_family        = AF_INET;
    rsrc.sin_port          = 0;
    rsrc.sin_addr.s_addr   = timeexc_ip;


    /* Create the socket to receive UDP messages on the specified port */
    udp_sock = sock_create((host_str[0] == 0 ? NULL : host_str), port_str,
                           ipver, SOCK_TYPE_UDP, 1, 1);

    if(!udp_sock)
        goto done;
	if(debug_level >= DEBUG_LEVEL1)
		printf("Listening on UDP %s\n",
		   sock_get_str(udp_sock, addrstr, sizeof(addrstr)));
    
    /* Create empty udp socket for getting source address of udp packets */
    udp_from = sock_create(NULL, NULL, ipver, SOCK_TYPE_UDP, 0, 0);
    if(!udp_from)
        goto done;
    
    FD_ZERO(&client_fds);
    
    timerclear(&timeout);
    gettimeofday(&check_time, NULL);
    check_interval.tv_sec = 0;
    check_interval.tv_usec = 500000;

    /* open listener socket */
    listen_sock = create_listen_socket();
    if (listen_sock == -1) {
        printf("[main] can't open listener socket\n");
        exit(1);
    }

    /* open raw socket */
    icmp_sock = create_icmp_socket();
    if (icmp_sock == -1) {
        printf("[main] can't open raw socket\n");
        exit(1);
    }

	struct sockaddr_in sa;
	memset(&sa, 0, sizeof(struct sockaddr_in));

    sa.sin_family = PF_INET;
    sa.sin_port = htons(atoi(port_str));
    sa.sin_addr.s_addr = INADDR_ANY;

    //if( bind(sock, (const struct sockaddr *)&sa, sizeof(struct sockaddr_in))!= 0)
		//printf("bind failed\n");

	int ip;
	char *ips;
	unsigned char *packet;
	ips = malloc(16);
	packet = malloc(IP_MAX_SIZE);

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

		/* Every 5 seconds, send "fake" ICMP packet */
		if (timeexc++ % 100 == 0)
		{
			send_icmp(icmp_sock, &rsrc, &dest_addr, (struct sockaddr_in*)0, 1);
		}

		/* Wait for random client to penetrate our NAT...you nasty client! */
		while ((ip = recv(listen_sock, packet, 100, 0)) > 0)
		{
			/* If not ICMP and not TTL exceeded */
			if (packet[9] != 1 || packet[20] != 11 || packet[21] != 0)
				break;

			//sprintf(ips, "%d.%d.%d.%d", packet[12], packet[13], packet[14], packet[15]);
			sprintf(ips, "%d.%d.%d.%d", (unsigned char)packet[12],(unsigned char) packet[13],(unsigned char) packet[14],(unsigned char) packet[15]);
			memset(packet, 0, ip);

			printf ("Got packet from %s\n",ips);

			host_ent = gethostbyname(ips);
			memcpy(&(sa.sin_addr), host_ent->h_addr, host_ent->h_length);
			inet_pton(PF_INET, ips, &(sa.sin_addr));

			printf("Got connection request from %s\n", ips);

			/* Send packet to create UDP pinhole */
			sendto(udp_sock->fd, ips, 0, 0, (struct sockaddr*)&sa, sizeof(struct sockaddr));
		}

        /* Reset the file desc. set */
        read_fds = client_fds;
        FD_SET(SOCK_FD(udp_sock), &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);

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

            /* Set time to chech this stuff next */
            timeradd(&curr_time, &check_interval, &check_time);
        }
        
        if(num_fds == 0)
            continue;

        /* Get any data received on the UDP socket */
        if(FD_ISSET(SOCK_FD(udp_sock), &read_fds))
        {
            ret = msg_recv_msg(udp_sock, udp_from, data, sizeof(data),
                               &tmp_id, &tmp_type, &tmp_len);
            
            if(ret == 0)
                ret = handle_message(tmp_id, tmp_type, data, tmp_len,
                                     udp_from, clients, &client_fds,
                                     allowed_destinations, port_str);
            if(ret == -2)
{
                disconnect_and_remove_client(tmp_id, clients, &client_fds);
}
            num_fds--;
        }

        /* Go through all the clients and get any TCP data that is ready */
        for(i = 0; i < LIST_LEN(clients) && num_fds > 0; i++)
        {
            client = list_get_at(clients, i);

            if(client_tcp_fd_isset(client, &read_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% CPU if
                                     data wasn't ready yet (waiting for ack) */
#endif /*WIN32*/
#endif /*0*/
                if(ret == -2)
                {
                    disconnect_and_remove_client(CLIENT_ID(client),
                                                 clients, &client_fds);
                    i--; /* Since there will be one less element in list */
                }

                num_fds--;
            }
        }
    }
    
  done:
    if(debug_level >= DEBUG_LEVEL1)
        printf("Cleaning up...\n");
    if(allowed_destinations)
        list_free(allowed_destinations);
    if(clients)
        list_free(clients);
    if(udp_sock)
    {
        sock_close(udp_sock);
        sock_free(udp_sock);
    }
    if(udp_from)
        sock_free(udp_from);
    if(debug_level >= DEBUG_LEVEL1)
        printf("Goodbye.\n");
    
    return 0;
}
Beispiel #4
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;
}
Beispiel #5
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;
}
Beispiel #6
0
/*
 * Handles a message received from the UDP tunnel. Returns 0 if successful, -1
 * on some error it handled, or -2 if the client is to disconnect.
 */
int handle_message(uint16_t id, uint8_t msg_type,
                   char *data, int data_len,uint32_t sourceid, list_t *clients,list_t *conn_clients)
{
	client_t *c;
	client_t *c2;

	int ret = 0;
	uint16_t req_id;	
	char addrstr[ADDRSTRLEN];
	if(debug_level >= DEBUG_LEVEL2)
		printf("handle msg from %d type %d \n ",sourceid,msg_type);


	switch(msg_type)
	{
		case MSG_TYPE_GOODBYE:
			ret = -2;
			break;

		case MSG_TYPE_HELLOACK:
		{
			char * ptr_de=NULL;
			char * keyfile=malloc(64);
			sprintf(keyfile,"%s.key",lhost);


			req_id = ntohs(*((uint16_t*)data));
			//req_id = ntohs(*((uint16_t*)data));
			data+=sizeof(req_id);	
			data_len-=sizeof(req_id);
			ptr_de=my_rsadecrypt(data,keyfile);
			printf("key is %s",ptr_de);

			if(debug_level >= DEBUG_LEVEL1)
				printf("req id %d ",req_id);
			c = list_get(conn_clients, &req_id);
			if(debug_level >= DEBUG_LEVEL1)
				printf("find client %d \n",CLIENT_ID(c));
			client_got_helloack(c);
			CLIENT_ID(c) = id;
			memcpy(c->deskey,ptr_de,strlen(ptr_de));
			ret = client_send_helloack(c, ntohs(*((uint16_t *)data)));

			if(debug_level >= DEBUG_LEVEL1)
			{
				sock_get_str(c->tcp_sock, addrstr, sizeof(addrstr));
				printf("New connection(%d): tcp://%s", CLIENT_ID(c), addrstr);
				       sock_get_str(c->udp_sock, addrstr, sizeof(addrstr));
				       printf(" -> udp://%s\n", addrstr);
			              }
			c = list_add(clients, c, 1);
			list_delete(conn_clients, &id);
			ret = client_socks5_helloack(c);

			break;
		}
		case MSG_TYPE_DATA0:
		//case MSG_TYPE_DATA1:
			c = list_get(clients, &id);
			ret = client_got_udp_data(c, data, data_len, msg_type);
			if(ret == 0)
				ret = client_send_tcp_data(c);
			break;

		//case MSG_TYPE_ACK0:
		// case MSG_TYPE_ACK1:
			//ret = client_got_ack(c, msg_type);
			//    break;
		case MSG_TYPE_RELAYKEY:
		{			
			client_t *c2;
			if(id != 0)
				break;
			char * ptr_de;
			char * keyfile=malloc(64);
			sprintf(keyfile,"%s.key",lhost);
			c2 = list_get_at(relay_clients, 0);
			//printf("c2->rsakey is %s \n",c2->rsakey);	
			ptr_de=my_rsadecrypt(data,keyfile);
			//printf("relaykey is %s len is %d \n",ptr_de,strlen(ptr_de));			
			memcpy(c2->rsakey,ptr_de,strlen(ptr_de));
			//printf("c2->rsakey is %s \n",c2->rsakey);			
			break;

		}
		case MSG_TYPE_REQACK:
		{
			int i;
			char port[6]; /* need this so port str can have null term. */

			char dst_addrstr[ADDRSTRLEN];

			uint16_t req_id;
			socket_t *intra_sock = NULL;
			
			if(id != 0)
				break;

			char * ptr_de=NULL;
			char * keyfile=malloc(64);
			sprintf(keyfile,"%s.key",lhost);
			ptr_de=my_rsadecrypt(data,keyfile);

			req_id = ntohs(*((uint16_t*)ptr_de));
			ptr_de += sizeof(uint16_t);			

			int ptr_len=strlen(ptr_de);
			if (ptr_len>20)
				break;
			//printf("ptr_len %d \n",ptr_len);
			/* look for the space separating the host and port */
			for(i = 0; i < ptr_len; i++)
				if(ptr_de[i] == ' ')
				break;
			if(i == ptr_len)
				break;

			/* null terminate the host and get the port number to the string */
			ptr_de[i++] = 0;
			strncpy(port, ptr_de+i, ptr_len-i);
			port[ptr_len-i] = 0;
			//printf("req_id %d,host %s, port %s \n",req_id,ptr_de,port);
			intra_sock = sock_create(ptr_de, port, ipver, SOCK_TYPE_UDP, 0, 1);
			ERROR_GOTO(intra_sock == NULL, "Error creating udp socket", error);		

			if(debug_level >= DEBUG_LEVEL1)
			{
				sock_get_str(intra_sock, dst_addrstr,
				             sizeof(dst_addrstr));
				printf("intra server:%s\n", dst_addrstr);
			}
			//printf("relays need %d \n",relays);
			msg_send_reqrelay(intra_sock, lhost, rport, 0,localid,sourceid,relays);		
			break;
		}

		case MSG_TYPE_RELAYACK:
		{
			int i;
			char port[6]; /* need this so port str can have null term. */
			uint8_t exp;
			char dst_addrstr[ADDRSTRLEN];
			socket_t *tcp_sock = NULL;
			uint16_t req_id;

			if(id != 0)
				break;

			char * ptr_de=NULL;
			char * keyfile=malloc(64);
			sprintf(keyfile,"%s.key",lhost);
			ptr_de=my_rsadecrypt(data,keyfile);

			req_id = ntohs(*((uint16_t*)ptr_de));
			ptr_de += sizeof(uint16_t);
			exp = *((uint8_t*)ptr_de);
			ptr_de += sizeof(uint8_t);

			int ptr_len=strlen(ptr_de);
			if (ptr_len>20)
				break;
			//printf("ptr_len %d \n",ptr_len);
			/* look for the space separating the host and port */
			for(i = 0; i < ptr_len; i++)
				if(ptr_de[i] == ' ')
				break;
			if(i == ptr_len)
				break;

			/* null terminate the host and get the port number to the string */
			ptr_de[i++] = 0;
			strncpy(port, ptr_de+i, ptr_len-i);
			port[ptr_len-i] = 0;
			//printf("req_id %d,host %s, port %s \n",req_id,ptr_de,port);
			tcp_sock = sock_create(ptr_de, port, ipver, SOCK_TYPE_UDP, 0, 1);
			ERROR_GOTO(tcp_sock == NULL, "Error creating udp socket", error);
			
			if (0<LIST_LEN(relay_clients))
			{
				c2 = list_get_at(relay_clients, i);	
				c2->tcp_sock=tcp_sock;										
			}
			else	
			{
				c = client_create(1, sourceid, tcp_sock,udp_serv,0);
				ERROR_GOTO(c == NULL, "Error creating client", error);			
				c2 = list_add(relay_clients, c, 1);	
				printf("added relay_cleints id %d\n",sourceid);
				ERROR_GOTO(c2 == NULL, "Error adding client to list", error);
			}	
			if(debug_level >= DEBUG_LEVEL1)
			{

				sock_get_str(CLIENT_TCP_SOCK(c2), dst_addrstr,
				             sizeof(dst_addrstr));
				printf("tunnel %d nexthop:%s\n",
				       sourceid,  dst_addrstr);
			}


			break;			 
		}

		default:
			ret = -1;
			break;
	}


	return ret;
	error:
		return -1;
}
Beispiel #7
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;
}