Date: Wed, 13 Jul 2011 14:37:26 +0400 From: Vladimir Budnev <vladimir.budnev@gmail.com> To: freebsd-net@freebsd.org Subject: (TCP/IP) Server side sends RST after 3-way handshake.Syn flood defense or queue overflow? Message-ID: <CAAvRK97hwamb8mpu6G6FEbkYATQ3BWNZoFYbsvmgKDwHNXFsLA@mail.gmail.com>
next in thread | raw e-mail | index | archive | help
Hello. Iv faced some problem and seems don't realize the mechanincs why does it occures. First of all i'd like to notice that my freebsd knowledge and expirience is limited, especially in such "strange" cases. In details(code example ill be at the end): System: # uname -spr FreeBSD 7.2-RELEASE amd64 We have simple TCP client and server. Server is very casual, it listens on some port in while->select->accept loop. Client knocks on server port and sends some data and closes the port. First it was designed for sending data 3-5/times per minute. But once during test I'v noticed that if client sends data very fast (more precisely it opens and closes socket to server very fast) there is "54 - Connection reset by peer" error on call to "connect".(on client side ofc) Some illustration from tcpdump: (test on localhost.server side is port 10002.i'v cuted other fields for simplicity) <...> 13:48:58.491229 IP 127.0.0.1.56677 > 127.0.0.1.10002: S 13:48:58.491255 IP 127.0.0.1.10002 > 127.0.0.1.56677: S ack 13:48:58.491266 IP 127.0.0.1.56677 > 127.0.0.1.10002: . ack 13:48:58.491300 IP 127.0.0.1.56677 > 127.0.0.1.10002: P 13:48:58.491346 IP 127.0.0.1.56677 > 127.0.0.1.10002: F 13:48:58.491365 IP 127.0.0.1.10002 > 127.0.0.1.56677: . ack 13:48:58.491466 IP 127.0.0.1.55238 > 127.0.0.1.10002: S // 13:48:58.491490 IP 127.0.0.1.10002 > 127.0.0.1.55238: S ack // handshake 13:48:58.491503 IP 127.0.0.1.55238 > 127.0.0.1.10002: . ack // 13:48:58.491536 IP 127.0.0.1.55238 > 127.0.0.1.10002: P <--data 13:48:58.491580 IP 127.0.0.1.55238 > 127.0.0.1.10002: F <-- client closes session 13:48:58.491599 IP 127.0.0.1.10002 > 127.0.0.1.55238: . ack // OK 13:48:58.491701 IP 127.0.0.1.60212 > 127.0.0.1.10002: S 13:48:58.491726 IP 127.0.0.1.10002 > 127.0.0.1.60212: S ack 13:48:58.491738 IP 127.0.0.1.60212 > 127.0.0.1.10002: . ack 13:48:58.491745 IP 127.0.0.1.10002 > 127.0.0.1.60212: R <-- this is strange answer.Why? 13:48:58.491887 IP 127.0.0.1.60804 > 127.0.0.1.10002: S 13:48:58.491914 IP 127.0.0.1.10002 > 127.0.0.1.60804: S ack 13:48:58.491924 IP 127.0.0.1.60804 > 127.0.0.1.10002: . ack 13:48:58.491931 IP 127.0.0.1.10002 > 127.0.0.1.60804: R <...> Some connections were OK but then server application begin to send RST right after handshake. Tuning listen backlog parameter doesn't help much, BUT what really solves the "problem" is increasing time interval between client requests.egusleep(10000) solves the "problem" at all. Iv maned for some tuning like syncache and syncookies but nothing usefull, or i missed something.But here they are: # sysctl -a | grep syncache net.inet.tcp.syncache.rst_on_sock_fail: 1 net.inet.tcp.syncache.rexmtlimit: 3 net.inet.tcp.syncache.hashsize: 512 net.inet.tcp.syncache.count: 0 net.inet.tcp.syncache.cachelimit: 15360 net.inet.tcp.syncache.bucketlimit: 30 ipfw rules allows any from any, nothing special. QUESTION: So the question is why such thing happening?Is this is some freebsd defense from syn flood?(to be honest don't think so because seems there is no fixed "ALLOWED syn/syn-ack/ack per seconds"). It more looks like some queue overflow,but I don't know what queue and how it can be enlarged. If i can provide some more info to clear some aspects I will! Thanks in advance, Vladimir. I'v wrote some simplified(as simply as possible imho:)) small client and server example which reproduses the situation (at least on our test stend), here is the code. its not perfect, but i think its easy to read as example: NOTICE: it writes logs to local0 level. //------------------------------------------------------------------------------ //------------------------------------client.c //------------------------------------------------------------------------------ #include <sys/socket.h> #include <sys/types.h> #include <sys/wait.h> #include <stdlib.h> #include <syslog.h> #include <arpa/inet.h> #include <strings.h> #include <string.h> #include <netinet/in.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <errno.h> #include <signal.h> #include <ifaddrs.h> uint8_t progname[]="client"; #define MAX_ITER 300 int send_msg(); int main(int argc,char **argv){ int res=0; uint16_t counter=0; openlog(progname,LOG_NDELAY,LOG_LOCAL0); syslog(LOG_DEBUG,"Started"); while( counter<=MAX_ITER ){ syslog(LOG_DEBUG,"Attemp #%d",counter); send_msg(); counter++; } return res; } int send_msg(){ int sock; int res; struct sockaddr_in src_addr; struct sockaddr_in dst_addr; struct timeval tv; uint8_t target_addr[]="127.0.0.1"; uint8_t target_port[]="10002"; sock=socket(AF_INET,SOCK_STREAM,0); if(sock<0){ syslog(LOG_ERR,"ERROR on socket: %s\n",strerror(errno)); return -1; } src_addr.sin_family = AF_INET; src_addr.sin_port = htons(INADDR_ANY); src_addr.sin_addr.s_addr = INADDR_ANY; res=bind(sock,(struct sockaddr*)&src_addr,sizeof(struct sockaddr_in)); if(res<0){ syslog(LOG_ERR,"ERROR on bind: %s\n",strerror(errno)); close(sock); return -1; } dst_addr.sin_family = AF_INET; dst_addr.sin_port = htons(atoi(target_port)); dst_addr.sin_addr.s_addr = inet_addr(target_addr); syslog(LOG_DEBUG,"Connecting to addr %s : %s",target_addr,target_port); res=connect(sock,(struct sockaddr *)&dst_addr,sizeof(struct sockaddr_in)); if (res<0){ syslog(LOG_ERR,"ERROR: connection to server failed: %d - %s",errno,strerror(errno)); close(sock); return -1; } close(sock); return 0; } //------------------------------------------------------------------------------ //--------------------------server.c //------------------------------------------------------------------------------ #include <sys/socket.h> #include <sys/types.h> #include <sys/wait.h> #include <stdlib.h> #include <syslog.h> #include <arpa/inet.h> #include <strings.h> #include <string.h> #include <netinet/in.h> #include <unistd.h> #include <stdio.h> #include <fcntl.h> #include <errno.h> #include <signal.h> #include <ifaddrs.h> #define SELECT_TIMEOUT_S 10 uint8_t progname[]="server"; int wait_loop(uint8_t*,uint16_t); int main(int argc,char **argv){ int res=0; openlog(progname,LOG_NDELAY,LOG_LOCAL0); syslog(LOG_DEBUG,"Started"); res=wait_loop( "127.0.0.1",atoi("10002") ); return res; } int wait_loop(uint8_t* listen_ip,uint16_t listen_port) { int32_t listen_sock; int32_t client_sock; struct sockaddr_in listen_addr; int res; fd_set readfds; pid_t process_id; struct timeval tv; uint32_t client_addr_size=sizeof(struct sockaddr_in); struct sockaddr_in client_addr; listen_sock=socket(AF_INET,SOCK_STREAM,0); if(listen_sock<0){ syslog(LOG_ERR,"ERROR on select: %s\n",strerror(errno)); return -1; } listen_addr.sin_family = AF_INET; listen_addr.sin_port = htons(listen_port); listen_addr.sin_addr.s_addr = inet_addr(listen_ip); res=bind(listen_sock,(struct sockaddr*)&listen_addr,sizeof(struct sockaddr_in)); if(res<0){ syslog(LOG_ERR,"ERROR on bind: %s\n",strerror(errno)); close(listen_sock); return -1; } res=listen(listen_sock,100); // just for example,tuning this doesnt help much if(res<0){ syslog(LOG_ERR,"ERROR on listen: %s\n",strerror(errno)); close(listen_sock); return -1; } syslog(LOG_DEBUG,"Listening at %s:%d",listen_ip,listen_port); while(1) { FD_ZERO(&readfds); FD_SET(listen_sock,&readfds); tv.tv_sec=SELECT_TIMEOUT_S; tv.tv_usec=0; res=select(listen_sock+1,&readfds,0,0,&tv); if ( res!=-1 && FD_ISSET( listen_sock,&readfds ) ){ client_sock=accept(listen_sock,(struct sockaddr*)&client_addr,&client_addr_size); if( client_sock<0 ){ syslog(LOG_ERR,"ERROR on accept: %s\n",strerror(errno)); } syslog(LOG_DEBUG,"Request from: %s:%d\n",inet_ntoa(client_addr.sin_addr),client_addr.sin_port); usleep(100000);// some useful job here which take some time to execute :) close(client_sock); }//select if }//while loop return 0; }
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?CAAvRK97hwamb8mpu6G6FEbkYATQ3BWNZoFYbsvmgKDwHNXFsLA>