Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 2 Sep 2004 06:07:48 GMT
From:      Dmitry Dvoinikov <dmitry@targeted.org>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   kern/71274: Frequent bind()/connect()'s assign same local ports to different sockets
Message-ID:  <200409020607.i8267mld064901@www.freebsd.org>
Resent-Message-ID: <200409020610.i826AKup007296@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         71274
>Category:       kern
>Synopsis:       Frequent bind()/connect()'s assign same local ports to different sockets
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Sep 02 06:10:20 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator:     Dmitry Dvoinikov
>Release:        4.10-RELEASE
>Organization:
-
>Environment:
FreeBSD  4.10-RELEASE FreeBSD 4.10-RELEASE #0: Tue May 25 22:47:12 GMT 2004     root@perseus.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  i386
>Description:
1. A program keeps looping forever creating TCP sockets and connecting them to some TCP server in a connect/send/recv/close fashion (sample uses HTTP server at localhost).
2. Each outgoing socket is assigned a local port number, either explicitly (with bind to zero port before connect) or implicitly (within connect).
3. After this program runs for a while, it happens that another port number assigned has just been used a few connects ago (and that used socket is probably not free, but is still alive in TIME_WAIT or some other near-terminal state). Therefore this second connect gets a port number which is not free, and therefore connect fails returning "Connection refused".
4. This is not a resource exhaustion problem, as netstat output shows only around a thousand sockets.
5. This is not a congestion problem, because the looping program is single-threaded and can't produce more than one connection at a time.
      
>How-To-Repeat:
Compile an run this program, having http server at localhost:80 (I used thttpd for it's lightweightness, but even http doesn't really matter of course, it's just any TCP server). Examine program's output for the following pattern:

bound to 2664
bound to 1267 <<<<< REPEATS
bound to 4646
bound to 3060
bound to 1374
bound to 4986
bound to 1267 <<<<< REPEATS
connect failed: Connection refused

------------------------------------------------
base64 encoded sample:
------------------------------------------------
begin-base64 644 test.c
I2luY2x1ZGUgPHN5cy90eXBlcy5oPgojaW5jbHVkZSA8c3lzL3NvY2tldC5oPgojaW5jbHVkZSA8
c3RkaW8uaD4KI2luY2x1ZGUgPHVuaXN0ZC5oPgojaW5jbHVkZSA8c3RkbGliLmg+CiNpbmNsdWRl
IDxuZXRpbmV0L2luLmg+CiNpbmNsdWRlIDxzdHJpbmcuaD4KI2luY2x1ZGUgPGVycm5vLmg+CiNp
bmNsdWRlIDxzeXMvcGFyYW0uaD4KCmNoYXIqIFJFUVVFU1QgPSAiR0VUIC8gSFRUUC8xLjBcclxu
XHJcbiI7CgppbnQgbWFpbigpCnsKCiAgICAgICAgaW50IHMsIHVudXNlZDsKICAgICAgICBzdHJ1
Y3Qgc29ja2FkZHJfaW4gYTsKICAgICAgICBjaGFyIGJ1ZlsxMDI0XTsKCiAgICAgICAgbWVtc2V0
KCZhLCAwLCBzaXplb2Yoc3RydWN0IHNvY2thZGRyX2luKSk7CiAgICAgICAgYS5zaW5fbGVuID0g
c2l6ZW9mKHN0cnVjdCBzb2NrYWRkcl9pbik7CiAgICAgICAgYS5zaW5fZmFtaWx5ID0gQUZfSU5F
VDsKICAgICAgICBhLnNpbl9hZGRyLnNfYWRkciA9IGh0b25sKDB4N2YwMDAwMDEpOwoKICAgICAg
ICB3aGlsZSAoMSkKICAgICAgICB7CgogICAgICAgICAgICAgICAgcyA9IHNvY2tldChQRl9JTkVU
LCBTT0NLX1NUUkVBTSwgMCk7CgkJaWYgKHMgPT0gLTEpCgkJewoJCQlmcHJpbnRmKHN0ZG91dCwg
InNvY2tldCBmYWlsZWQ6ICVzXG4iLCBzdHJlcnJvcihlcnJubykpOwoJCQljb250aW51ZTsKCQl9
CgogICAgICAgICAgICAgICAgYS5zaW5fcG9ydCA9IDA7CiAgICAgICAgICAgICAgICBpZiAoYmlu
ZChzLCAoc3RydWN0IHNvY2thZGRyKikmYSwgc2l6ZW9mKHN0cnVjdCBzb2NrYWRkcl9pbikpID09
IC0xKQoJCXsKCQkJY2xvc2Uocyk7CiAgICAgICAgICAgICAgICAgICAgICAgIGZwcmludGYoc3Rk
b3V0LCAiYmluZCBmYWlsZWQ6ICVzXG4iLCBzdHJlcnJvcihlcnJubykpOyAKICAgICAgICAgICAg
ICAgICAgICAgICAgY29udGludWU7CgkJfQoKICAgICAgICAgICAgICAgIHVudXNlZCA9IHNpemVv
ZihzdHJ1Y3Qgc29ja2FkZHJfaW4pOwogICAgICAgICAgICAgICAgaWYgKGdldHNvY2tuYW1lKHMs
IChzdHJ1Y3Qgc29ja2FkZHIqKSZhLCAmdW51c2VkKSA9PSAtMSkKCQl7CiAgICAgICAgICAgICAg
ICAgICAgICAgIGNsb3NlKHMpOwogICAgICAgICAgICAgICAgICAgICAgICBmcHJpbnRmKHN0ZG91
dCwgImdldHNvY2tuYW1lIGZhaWxlZDogJXNcbiIsIHN0cmVycm9yKGVycm5vKSk7ICAgICAgICAg
ICAgICAgICAgIAogICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsgCgkJfQoKICAgICAg
ICAgICAgICAgIGZwcmludGYoc3Rkb3V0LCAiYm91bmQgdG8gJWRcbiIsICh1bnNpZ25lZCBsb25n
KW50b2hzKGEuc2luX3BvcnQpKTsKCiAgICAgICAgICAgICAgICBhLnNpbl9wb3J0ID0gaHRvbnMo
ODApOwogICAgICAgICAgICAgICAgaWYgKGNvbm5lY3QocywgKHN0cnVjdCBzb2NrYWRkciopJmEs
IHNpemVvZihzdHJ1Y3Qgc29ja2FkZHJfaW4pKSA9PSAtMSkKICAgICAgICAgICAgICAgIHsKICAg
ICAgICAgICAgICAgICAgICAgICAgY2xvc2Uocyk7CiAgICAgICAgICAgICAgICAgICAgICAgIGZw
cmludGYoc3Rkb3V0LCAiY29ubmVjdCBmYWlsZWQ6ICVzXG4iLCBzdHJlcnJvcihlcnJubykpOwog
ICAgICAgICAgICAgICAgICAgICAgICBjb250aW51ZTsKICAgICAgICAgICAgICAgIH0KCiAgICAg
ICAgICAgICAgICBzZW5kKHMsIFJFUVVFU1QsIHN0cmxlbihSRVFVRVNUKSwgMCk7CiAgICAgICAg
ICAgICAgICB3aGlsZSAocmVjdihzLCBidWYsIHNpemVvZihidWYpLCAwKSA+IDApIHsgfQogICAg
ICAgICAgICAgICAgY2xvc2Uocyk7CgogICAgICAgIH0KCn0KCg==
====
------------------------------------------------
plain (broken ?) sample:
------------------------------------------------
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include <sys/param.h>

char* REQUEST = "GET / HTTP/1.0\r\n\r\n";

int main()
{

        int s, unused;
        struct sockaddr_in a;
        char buf[1024];

        memset(&a, 0, sizeof(struct sockaddr_in));
        a.sin_len = sizeof(struct sockaddr_in);
        a.sin_family = AF_INET;
        a.sin_addr.s_addr = htonl(0x7f000001);

        while (1)
        {

                s = socket(PF_INET, SOCK_STREAM, 0);
                if (s == -1)
                {
                        fprintf(stdout, "socket failed: %s\n", strerror(errno));
                        continue;
                }

                a.sin_port = 0;
                if (bind(s, (struct sockaddr*)&a, sizeof(struct sockaddr_in)) == -1)
                {
                        close(s);
                        fprintf(stdout, "bind failed: %s\n", strerror(errno)); 
                        continue;
                }

                unused = sizeof(struct sockaddr_in);
                if (getsockname(s, (struct sockaddr*)&a, &unused) == -1)
                {
                        close(s);
                        fprintf(stdout, "getsockname failed: %s\n", strerror(errno));                   
                        continue; 
                }

                fprintf(stdout, "bound to %d\n", (unsigned long)ntohs(a.sin_port));

                a.sin_port = htons(80);
                if (connect(s, (struct sockaddr*)&a, sizeof(struct sockaddr_in)) == -1)
                {
                        close(s);
                        fprintf(stdout, "connect failed: %s\n", strerror(errno));
                        continue;
                }

                send(s, REQUEST, strlen(REQUEST), 0);
                while (recv(s, buf, sizeof(buf), 0) > 0) { }
                close(s);

        }

}
------------------------------------------------

      
>Fix:
      
>Release-Note:
>Audit-Trail:
>Unformatted:



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200409020607.i8267mld064901>