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; }
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; }