(TCP/IP) Server side sends RST after 3-way handshake.Syn flood defense or queue overflow?

Vladimir Budnev vladimir.budnev at gmail.com
Wed Jul 13 11:04:09 UTC 2011


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


More information about the freebsd-net mailing list