How to avoid DOS attack in this code?
asyncsocket, c++, ddos, recv, sockets
Solution
I don't think there is any 100% effective software solution to DOS attacks in general; no matter what you do, someone could always throw more packets at your network interface than it can handle.
In this particular case, though, it looks like your program can only handle one connection at a time -- that is, incoming connection #2 won't be processed until connection #1 has completed its transaction (or timed out). So that's an obvious choke point -- all an attacker has to do is connect to your server and then do nothing, and your server is effectively disabled for (however long your timeout period is).
To avoid that you would need to rewrite the server code to handle multiple TCP connections at once. You could either do that by switching to non-blocking I/O (by passing O_NONBLOCK flag to fcntl()), and using select() or poll() or etc to wait for I/O on multiple sockets at once, or by spawning multiple threads or sub-processes to handle incoming connections in parallel, or by using async I/O. (I personally prefer the first solution, but all can work to varying degrees). In the first approach it is also practical to do things like forcibly closing any existing sockets from a given IP address before accepting a new socket from that IP address, which means that any given attacking computer could only tie up a maximum of one socket on your server at a time, which would make it harder for that person to DOS your machine unless he had access to a number of client machines.
You might read this article for more discussion about handling many TCP connections at the same time.
Problem
I have a code written in C/C++ that look like this: ``` while(1) { //Accept struct sockaddr_in client_addr; int client_fd = this->w_accept(&client_addr); char client_ip[64]; int client_port = ntohs(client_addr.sin_port); inet_ntop(AF_INET, &client_addr.sin_addr, client_ip, sizeof(client_ip)); //Listen first string char firststring[512]; memset(firststring,0,512); if(this->recvtimeout(client_fd,firststring,sizeof(firststring),u->timeoutlogin) < 0){ close(client_fd); } if(strcmp(firststring,"firststr")!=0) { cout << "Disconnected!" << endl; close(client_fd); continue; } //Send OK first string send(client_fd, "OK", 2, 0); //Listen second string char secondstring[512]; memset(secondstring,0,512); if(this->recvtimeout(client_fd,secondstring,sizeof(secondstring),u->timeoutlogin) < 0){ close(client_fd); } if(strcmp(secondstring,"secondstr")!=0) { cout << "Disconnected!!!" << endl; close(client_fd); continue; } //Send OK second string send(client_fd, "OK", 2, 0); } } ``` So, it's dossable. I've write a very simple dos script in perl that takedown the server. ``` #Evildos.pl use strict; use Socket; use IO::Handle; sub dosfunction { my $host = shift || '192.168.4.21'; my $port = 1234; my $firststr = 'firststr'; my $secondstr = 'secondstr'; my $protocol = getprotobyname('tcp'); $host = inet_aton($host) or die "$host: unknown host"; socket(SOCK, AF_INET, SOCK_STREAM, $protocol) or die "socket() failed: $!"; my $dest_addr = sockaddr_in($port,$host); connect(SOCK,$dest_addr) or die "connect() failed: $!"; SOCK->autoflush(1); print SOCK $firststr; #sleep(1); print SOCK $secondstr; #sleep(1); close SOCK; } my $i; for($i=0; $i<30;$i++) { &dosfunction; } ``` With a loop of 30 times, the server goes down. The question is: is there a method, a system, a solution that can avoid this type of attack? EDIT: recvtimeout ``` int recvtimeout(int s, char *buf, int len, int timeout) { fd_set fds; int n; struct timeval tv; // set up the file descriptor set FD_ZERO(&fds); FD_SET(s, &fds); // set up the struct timeval for the timeout tv.tv_sec = timeout; tv.tv_usec = 0; // wait until timeout or data received n = select(s+1, &fds, NULL, NULL, &tv); if (n == 0){ return -2; // timeout! } if (n == -1){ return -1; // error } // data must be here, so do a normal recv() return recv(s, buf, len, 0); } ```