#include #include #include #include #include #include #include #include #include "memory.h" struct sockaddr_in serveraddr; socklen_t serveraddrlen; int serverport; struct sockaddr_in dupaddr; socklen_t dupaddrlen; struct sockaddr_in dup2addr; socklen_t dup2addrlen; struct sockaddr_in autoaddr; socklen_t autoaddrlen; int serversock; int dupsock; int dup2sock; int autosock; void bindserver(void) { int bindres; int gsnres; char *serveraddrstr; memset(&serveraddr, '\0', sizeof(serveraddr)); #ifdef __FreeBSD__ serveraddr.sin_len = sizeof(serveraddr); #endif serveraddr.sin_family = AF_INET; serveraddr.sin_port = 0; serveraddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); serveraddrlen = sizeof(serveraddr); serversock = socket(PF_INET, SOCK_STREAM, 0); if (serversock < 0) { perror("server socket"); exit(1); } bindres = bind(serversock, (struct sockaddr *) &serveraddr, serveraddrlen); if (bindres != 0) { perror("server bind"); exit(1); } memset(&serveraddr, '\0', sizeof(serveraddr)); serveraddrlen = sizeof(serveraddr); gsnres = getsockname(serversock, (struct sockaddr *) &serveraddr, &serveraddrlen); if (gsnres != 0) { perror("server getsockname"); exit(1); } serverport = ntohs(serveraddr.sin_port); serveraddrstr = inet_ntoa(serveraddr.sin_addr); printf("serversock addr is %s:%d\n", serveraddrstr, serverport); } void binddup(void) { int bindres; int gsnres; int ssores; int dupport; int on; socklen_t onlen; char *dupaddrstr; int listenres; memcpy(&dupaddr, &serveraddr, sizeof(dupaddr)); dupaddrlen = sizeof(dupaddr); dupsock = socket(PF_INET, SOCK_STREAM, 0); if (dupsock < 0) { perror("dup socket"); exit(1); } on = 1; onlen = sizeof(on); ssores = setsockopt(dupsock, SOL_SOCKET, SO_REUSEADDR, &on, onlen); if (ssores != 0) { perror("dup setsockopt"); exit(1); } bindres = bind(dupsock, (struct sockaddr *) &dupaddr, dupaddrlen); if (bindres != 0) { perror("dup bind"); printf("This error was expected, tried to bind to used addr/port\n"); close(dupsock); dupsock = -1; return; } printf("BUG: binding duplicate socket to server addr/port succeeded\n"); memset(&dupaddr, '\0', sizeof(dupaddr)); dupaddrlen = sizeof(dupaddr); gsnres = getsockname(dupsock, (struct sockaddr *) &dupaddr, &dupaddrlen); if (gsnres != 0) { perror("dup getsockname"); exit(1); } dupport = ntohs(dupaddr.sin_port); if (dupport == serverport) { dupaddrstr = inet_ntoa(dupaddr.sin_addr); printf("dupsock addr is %s:%d\n", dupaddrstr, dupport); printf("bug triggered, " "address/port number conflict on sockets without SO_REUSEPORT\n"); listenres = listen(dupsock, 10); if (listenres == 0) printf("listen() succeeded after " "explicitly overlapping addr/port bind\n"); else perror("listen dupsock"); exit(1); } close(dupsock); dupsock = -1; } void binddup2(void) { int bindres; int gsnres; int ssores; int dup2port; int on; socklen_t onlen; char *dup2addrstr; int listenres; memset(&dup2addr, '\0', sizeof(dup2addr)); #ifdef __FreeBSD__ dup2addr.sin_len = sizeof(dup2addr); #endif dup2addr.sin_family = AF_INET; dup2addr.sin_port = htons(serverport); dup2addr.sin_addr.s_addr = htonl(INADDR_ANY); dup2addrlen = sizeof(dup2addr); dup2sock = socket(PF_INET, SOCK_STREAM, 0); if (dup2sock < 0) { perror("dup2 socket"); exit(1); } on = 1; onlen = sizeof(on); ssores = setsockopt(dup2sock, SOL_SOCKET, SO_REUSEADDR, &on, onlen); if (ssores != 0) { perror("dup2 setsockopt"); exit(1); } bindres = bind(dup2sock, (struct sockaddr *) &dup2addr, dup2addrlen); if (bindres != 0) { perror("dup2 bind"); printf("This error was expected, " "tried to bind to used port without SO_REUSEPORT\n"); close(dup2sock); dup2sock = -1; return; } printf("BUG: binding duplicate socket to server port succeeded\n"); memset(&dup2addr, '\0', sizeof(dup2addr)); dup2addrlen = sizeof(dup2addr); gsnres = getsockname(dup2sock, (struct sockaddr *) &dup2addr, &dup2addrlen); if (gsnres != 0) { perror("dup2 getsockname"); exit(1); } dup2port = ntohs(dup2addr.sin_port); if (dup2port == serverport) { dup2addrstr = inet_ntoa(dup2addr.sin_addr); printf("dup2sock addr is %s:%d\n", dup2addrstr, dup2port); printf("overlapping explicit bind to same port number " "succeeded without SO_REUSEPORT\n"); listenres = listen(dup2sock, 10); if (listenres == 0) printf("listen succeeded after explicitly overlapping port bind\n"); else perror("listen dup2sock"); } close(dup2sock); dup2sock = -1; } void bindloop(int iters) { int bindres; int gsnres; int ssores; int autoport; int on; socklen_t onlen; char *autoaddrstr; int listenres; for (;;) { if (iters == 0) break; iters--; memset(&autoaddr, '\0', sizeof(autoaddr)); #ifdef __FreeBSD__ autoaddr.sin_len = sizeof(autoaddr); #endif autoaddr.sin_family = AF_INET; autoaddr.sin_port = 0; autoaddr.sin_addr.s_addr = htonl(INADDR_ANY); autoaddrlen = sizeof(autoaddr); autosock = socket(PF_INET, SOCK_STREAM, 0); if (autosock < 0) { perror("auto socket"); exit(1); } on = 1; onlen = sizeof(on); ssores = setsockopt(autosock, SOL_SOCKET, SO_REUSEADDR, &on, onlen); if (ssores != 0) { perror("auto setsockopt"); exit(1); } bindres = bind(autosock, (struct sockaddr *) &autoaddr, autoaddrlen); if (bindres != 0) { perror("auto bind"); exit(1); } memset(&autoaddr, '\0', sizeof(autoaddr)); autoaddrlen = sizeof(autoaddr); gsnres = getsockname(autosock, (struct sockaddr *) &autoaddr, &autoaddrlen); if (gsnres != 0) { perror("auto getsockname"); exit(1); } autoport = ntohs(autoaddr.sin_port); if (autoport == serverport) { autoaddrstr = inet_ntoa(autoaddr.sin_addr); printf("autosock addr is %s:%d\n", autoaddrstr, autoport); printf("bug triggered, " "port number conflict on sockets without SO_REUSEPORT\n"); listenres = listen(autosock, 10); if (listenres == 0) printf("listen succeded after implicitly overlapping port bind\n"); else perror("listen autosock"); exit(1); } close(autosock); autosock = -1; } } int main(int argc, char **argv) { int iters = 16 * 1024 * 1024; bindserver(); listen(serversock, 10); binddup(); binddup2(); bindloop(iters); printf("bug not triggered after %d iterations\n", iters); return 0; }