[IPv6 since 2.6.12] connect() without bind() can't time out.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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]
  Powered by Linux