Home | History | Annotate | Download | only in net
      1 /*
      2  * Test for the regression introduced by
      3  *
      4  * b9470c27607b ("inet: kill smallest_size and smallest_port")
      5  *
      6  * If we open an ipv4 socket on a port with reuseaddr we shouldn't reset the tb
      7  * when we open the ipv6 conterpart, which is what was happening previously.
      8  */
      9 #include <errno.h>
     10 #include <error.h>
     11 #include <arpa/inet.h>
     12 #include <netinet/in.h>
     13 #include <stdbool.h>
     14 #include <stdio.h>
     15 #include <sys/socket.h>
     16 #include <sys/types.h>
     17 #include <unistd.h>
     18 
     19 #define PORT 9999
     20 
     21 int open_port(int ipv6, int any)
     22 {
     23 	int fd = -1;
     24 	int reuseaddr = 1;
     25 	int v6only = 1;
     26 	int addrlen;
     27 	int ret = -1;
     28 	struct sockaddr *addr;
     29 	int family = ipv6 ? AF_INET6 : AF_INET;
     30 
     31 	struct sockaddr_in6 addr6 = {
     32 		.sin6_family = AF_INET6,
     33 		.sin6_port = htons(PORT),
     34 		.sin6_addr = in6addr_any
     35 	};
     36 	struct sockaddr_in addr4 = {
     37 		.sin_family = AF_INET,
     38 		.sin_port = htons(PORT),
     39 		.sin_addr.s_addr = any ? htonl(INADDR_ANY) : inet_addr("127.0.0.1"),
     40 	};
     41 
     42 
     43 	if (ipv6) {
     44 		addr = (struct sockaddr*)&addr6;
     45 		addrlen = sizeof(addr6);
     46 	} else {
     47 		addr = (struct sockaddr*)&addr4;
     48 		addrlen = sizeof(addr4);
     49 	}
     50 
     51 	if ((fd = socket(family, SOCK_STREAM, IPPROTO_TCP)) < 0) {
     52 		perror("socket");
     53 		goto out;
     54 	}
     55 
     56 	if (ipv6 && setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&v6only,
     57 			       sizeof(v6only)) < 0) {
     58 		perror("setsockopt IPV6_V6ONLY");
     59 		goto out;
     60 	}
     61 
     62 	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr,
     63 		       sizeof(reuseaddr)) < 0) {
     64 		perror("setsockopt SO_REUSEADDR");
     65 		goto out;
     66 	}
     67 
     68 	if (bind(fd, addr, addrlen) < 0) {
     69 		perror("bind");
     70 		goto out;
     71 	}
     72 
     73 	if (any)
     74 		return fd;
     75 
     76 	if (listen(fd, 1) < 0) {
     77 		perror("listen");
     78 		goto out;
     79 	}
     80 	return fd;
     81 out:
     82 	close(fd);
     83 	return ret;
     84 }
     85 
     86 int main(void)
     87 {
     88 	int listenfd;
     89 	int fd1, fd2;
     90 
     91 	fprintf(stderr, "Opening 127.0.0.1:%d\n", PORT);
     92 	listenfd = open_port(0, 0);
     93 	if (listenfd < 0)
     94 		error(1, errno, "Couldn't open listen socket");
     95 	fprintf(stderr, "Opening INADDR_ANY:%d\n", PORT);
     96 	fd1 = open_port(0, 1);
     97 	if (fd1 >= 0)
     98 		error(1, 0, "Was allowed to create an ipv4 reuseport on a already bound non-reuseport socket");
     99 	fprintf(stderr, "Opening in6addr_any:%d\n", PORT);
    100 	fd1 = open_port(1, 1);
    101 	if (fd1 < 0)
    102 		error(1, errno, "Couldn't open ipv6 reuseport");
    103 	fprintf(stderr, "Opening INADDR_ANY:%d\n", PORT);
    104 	fd2 = open_port(0, 1);
    105 	if (fd2 >= 0)
    106 		error(1, 0, "Was allowed to create an ipv4 reuseport on a already bound non-reuseport socket");
    107 	close(fd1);
    108 	fprintf(stderr, "Opening INADDR_ANY:%d after closing ipv6 socket\n", PORT);
    109 	fd1 = open_port(0, 1);
    110 	if (fd1 >= 0)
    111 		error(1, 0, "Was allowed to create an ipv4 reuseport on an already bound non-reuseport socket with no ipv6");
    112 	fprintf(stderr, "Success");
    113 	return 0;
    114 }
    115