Hello.
I think timer check for TCP's "connect() without bind()" for IPv6
doesn't work when no local port is available.
I can run the following program for 2.4.30, 2.4.31, 2.4.32 and 2.6.11.
But I can't run it for 2.6.12 and later (including 2.6.16-rc2).
The stream socket enters to SYN_SENT state. But when there is no free
port in the range defined by /proc/sys/net/ipv4/ip_local_port_range,
the connect() call sleeps forever; even after some ports became free.
Other operations such as TCP's "bind() with port = 0",
UDP's "bind() with port = 0", UDP's "connect() without bind()",
UDP's "sendto() without bind()" return immediately
when no free port is available.
---- Start of code. -----
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
static void Test(unsigned short int port) {
int i = 0;
for (i = 0; ; i++) {
const int fd = socket(AF_INET6, SOCK_STREAM, 0);
struct sockaddr_in6 addr;
socklen_t size = sizeof(addr);
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_addr = in6addr_loopback;
addr.sin6_port = htons(port);
printf("i=%d\n", i); fflush(stdout);
if (connect(fd, (struct sockaddr *) &addr, sizeof(addr))) break;
if (getsockname(fd, (struct sockaddr *) &addr, &size)) {
printf("getsockname() failed.\n"); break;
}
}
printf("IPv6/TCP connect port exhausted at %d\n", i); fflush(stdout);
}
int main(int argc, char *argv[]) {
FILE *fp = fopen("/proc/sys/net/ipv4/ip_local_port_range", "r");
int original_range[2], narrow_range[2] = { 32768, 32768 + 100 };
if (!fp || fscanf(fp, "%u %u", &original_range[0], &original_range[1]) != 2) {
fprintf(stderr, "Can't open /proc/sys/net/ipv4/ip_local_port_range .\n");
exit(1);
}
fclose(fp);
if ((fp = fopen("/proc/sys/net/ipv4/ip_local_port_range", "w")) == NULL) {
fprintf(stderr, "Can't open /proc/sys/net/ipv4/ip_local_port_range .\n");
exit(1);
}
fprintf(fp, "%d %d\n", narrow_range[0], narrow_range[1]);
fclose(fp);
{
struct sockaddr_in6 addr;
socklen_t size = sizeof(addr);
pid_t pid;
const int listener = socket(AF_INET6, SOCK_STREAM, 0);
unsigned short int port;
memset(&addr, 0, sizeof(addr));
addr.sin6_family = AF_INET6;
addr.sin6_addr = in6addr_any;
addr.sin6_port = htons(0);
bind(listener, (struct sockaddr *) &addr, sizeof(addr));
getsockname(listener, (struct sockaddr *) &addr, &size);
port = ntohs(addr.sin6_port);
listen(listener, 512);
if ((pid = fork()) == 0) {
while (1) {
size_t size = sizeof(addr);
const int fd = accept(listener, (struct sockaddr *) &addr, &size);
fprintf(stderr, "accept=%d\n", fd);
}
}
close(listener);
Test(port);
kill(pid, SIGHUP);
}
if ((fp = fopen("/proc/sys/net/ipv4/ip_local_port_range", "w")) == NULL) {
fprintf(stderr, "Can't open /proc/sys/net/ipv4/ip_local_port_range .\n");
exit(1);
}
fprintf(fp, "%d %d\n", original_range[0], original_range[1]);
fclose(fp);
printf("Done.\n");
return 0;
}
---- End of code. -----
Regards.
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]